1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <argp.h>
21: #include <assert.h>
22: #include <error.h>
23: #include <errno.h>
24: #include <fcntl.h>
25: #include <libintl.h>
26: #include <locale.h>
27: #include <mcheck.h>
28: #include <search.h>
29: #include <stdint.h>
30: #include <stdbool.h>
31: #include <stdio.h>
32: #include <stdio_ext.h>
33: #include <stdlib.h>
34: #include <string.h>
35: #include <unistd.h>
36: #include <sys/cdefs.h>
37: #include <sys/uio.h>
38:
39: #include "iconvconfig.h"
40:
41:
42: #include "../version.h"
43:
44: #define PACKAGE _libc_intl_domainname
45:
46:
47:
48: #include "../intl/hash-string.h"
49:
50:
51:
52: struct module
53: {
54: char *fromname;
55: struct Strent *fromname_strent;
56: char *filename;
57: struct Strent *filename_strent;
58: const char *directory;
59: struct Strent *directory_strent;
60: struct module *next;
61: int cost;
62: struct Strent *toname_strent;
63: char toname[0];
64: };
65:
66: struct alias
67: {
68: char *fromname;
69: struct Strent *froment;
70: struct module *module;
71: struct Strent *toent;
72: char toname[0];
73: };
74:
75: struct name
76: {
77: const char *name;
78: struct Strent *strent;
79: int module_idx;
80: uint32_t hashval;
81: };
82:
83: struct name_info
84: {
85: const char *canonical_name;
86: struct Strent *canonical_strent;
87:
88: struct module *from_internal;
89: struct module *to_internal;
90:
91: struct other_conv_list
92: {
93: int dest_idx;
94: struct other_conv
95: {
96: gidx_t module_idx;
97: struct module *module;
98: struct other_conv *next;
99: } other_conv;
100: struct other_conv_list *next;
101: } *other_conv_list;
102: };
103:
104:
105:
106: static void print_version (FILE *stream, struct argp_state *state);
107: void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
108:
109:
110: static const char doc[] = N_("\
111: Create fastloading iconv module configuration file.");
112:
113:
114: static const char args_doc[] = N_("[DIR...]");
115:
116:
117: static error_t parse_opt (int key, char *arg, struct argp_state *state);
118:
119:
120: static char *more_help (int key, const char *text, void *input);
121:
122:
123: #define OPT_PREFIX 300
124: #define OPT_NOSTDLIB 301
125: static const struct argp_option options[] =
126: {
127: { "prefix", OPT_PREFIX, "PATH", 0, N_("Prefix used for all file accesses") },
128: { "output", 'o', "FILE", 0, N_("\
129: Put output in FILE instead of installed location\
130: (--prefix does not apply to FILE)") },
131: { "nostdlib", OPT_NOSTDLIB, NULL, 0,
132: N_("Do not search standard directories, only those on the command line") },
133: { NULL, 0, NULL, 0, NULL }
134: };
135:
136:
137: static struct argp argp =
138: {
139: options, parse_opt, args_doc, doc, NULL, more_help
140: };
141:
142:
143:
144: static int handle_dir (const char *dir);
145:
146:
147: static void add_builtins (void);
148:
149:
150: static void get_aliases (void);
151:
152:
153: static void get_modules (void);
154:
155:
156: static void generate_name_list (void);
157:
158:
159: static void generate_name_info (void);
160:
161:
162: static int write_output (void);
163:
164:
165:
166: static const char *prefix = "";
167:
168: static size_t prefix_len;
169:
170:
171: static const char *output_file;
172:
173: static size_t output_file_len;
174:
175:
176: static bool nostdlib;
177:
178:
179: static void *modules;
180:
181:
182: static void *aliases;
183:
184:
185: static void *names;
186:
187:
188: static int nnames;
189:
190:
191: static struct alias **alias_list;
192: static size_t nalias_list;
193: static size_t nalias_list_max;
194:
195:
196: static struct module **module_list;
197: static size_t nmodule_list;
198: static size_t nmodule_list_max;
199:
200:
201: static struct name_info *name_info;
202: static size_t nname_info;
203:
204:
205: static size_t nextra_modules;
206:
207:
208:
209: static struct
210: {
211: const char *from;
212: const char *to;
213: } builtin_alias[] =
214: {
215: #define BUILTIN_ALIAS(alias, real) \
216: { .from = alias, .to = real },
217: #define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
218: MinF, MaxF, MinT, MaxT)
219: #include <gconv_builtin.h>
220: };
221: #undef BUILTIN_ALIAS
222: #undef BUILTIN_TRANSFORMATION
223: #define nbuiltin_alias (sizeof (builtin_alias) / sizeof (builtin_alias[0]))
224:
225: static struct
226: {
227: const char *from;
228: const char *to;
229: const char *module;
230: int cost;
231: } builtin_trans[] =
232: {
233: #define BUILTIN_ALIAS(alias, real)
234: #define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
235: MinF, MaxF, MinT, MaxT) \
236: { .from = From, .to = To, .module = Name, .cost = Cost },
237: #include <gconv_builtin.h>
238: };
239: #undef BUILTIN_ALIAS
240: #undef BUILTIN_TRANSFORMATION
241: #define nbuiltin_trans (sizeof (builtin_trans) / sizeof (builtin_trans[0]))
242:
243:
244:
245: #ifndef MODULE_EXT
246: # define MODULE_EXT ".so"
247: #endif
248: static const char gconv_module_ext[] = MODULE_EXT;
249:
250:
251: extern void *xmalloc (size_t n) __attribute_malloc__;
252: extern void *xcalloc (size_t n, size_t m) __attribute_malloc__;
253: extern void *xrealloc (void *p, size_t n);
254:
255:
256:
257: struct Strtab;
258: struct Strent;
259:
260:
261: extern struct Strtab *strtabinit (void);
262:
263:
264: extern void strtabfree (struct Strtab *st);
265:
266:
267: extern struct Strent *strtabadd (struct Strtab *st, const char *str,
268: size_t len);
269:
270:
271: extern void *strtabfinalize (struct Strtab *st, size_t *size);
272:
273:
274: extern size_t strtaboffset (struct Strent *se);
275:
276:
277: static struct Strtab *strtab;
278:
279:
280:
281: int
282: main (int argc, char *argv[])
283: {
284: int remaining;
285: int status = 0;
286:
287:
288:
289: mtrace ();
290:
291:
292: setlocale (LC_ALL, "");
293:
294:
295: textdomain (_libc_intl_domainname);
296:
297:
298: argp_parse (&argp, argc, argv, 0, &remaining, NULL);
299:
300: if (nostdlib && remaining == argc)
301: error (2, 0, _("Directory arguments required when using --nostdlib"));
302:
303:
304: strtab = strtabinit ();
305:
306:
307: while (remaining < argc)
308: status |= handle_dir (argv[remaining++]);
309:
310: if (! nostdlib)
311: {
312:
313: char *path = strdupa (GCONV_PATH), *tp = strsep (&path, ":");
314: while (tp != NULL)
315: {
316: status |= handle_dir (tp);
317:
318: tp = strsep (&path, ":");
319: }
320: }
321:
322:
323:
324: add_builtins ();
325:
326:
327: get_aliases ();
328:
329:
330: get_modules ();
331:
332:
333: generate_name_list ();
334:
335:
336:
337: generate_name_info ();
338:
339:
340: if (status == 0)
341: status = write_output ();
342: else
343: error (1, 0, _("no output file produced because warnings were issued"));
344:
345: return status;
346: }
347:
348:
349:
350: static error_t
351: parse_opt (int key, char *arg, struct argp_state *state)
352: {
353: switch (key)
354: {
355: case OPT_PREFIX:
356: prefix = arg;
357: prefix_len = strlen (prefix);
358: break;
359: case 'o':
360: output_file = arg;
361: output_file_len = strlen (output_file);
362: break;
363: case OPT_NOSTDLIB:
364: nostdlib = true;
365: break;
366: default:
367: return ARGP_ERR_UNKNOWN;
368: }
369: return 0;
370: }
371:
372:
373: static char *
374: more_help (int key, const char *text, void *input)
375: {
376: switch (key)
377: {
378: case ARGP_KEY_HELP_EXTRA:
379:
380: return strdup (gettext ("\
381: For bug reporting instructions, please see:\n\
382: <http://www.gnu.org/software/libc/bugs.html>.\n"));
383: default:
384: break;
385: }
386: return (char *) text;
387: }
388:
389:
390:
391: static void
392: print_version (FILE *stream, struct argp_state *state)
393: {
394: fprintf (stream, "iconvconfig (GNU %s) %s\n", PACKAGE, VERSION);
395: fprintf (stream, gettext ("\
396: Copyright (C) %s Free Software Foundation, Inc.\n\
397: This is free software; see the source for copying conditions. There is NO\n\
398: warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
399: "), "2007");
400: fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
401: }
402:
403:
404: static int
405: alias_compare (const void *p1, const void *p2)
406: {
407: const struct alias *a1 = (const struct alias *) p1;
408: const struct alias *a2 = (const struct alias *) p2;
409:
410: return strcmp (a1->fromname, a2->fromname);
411: }
412:
413:
414: static void
415: new_alias (const char *fromname, size_t fromlen, const char *toname,
416: size_t tolen)
417: {
418: struct alias *newp;
419: void **inserted;
420:
421: newp = (struct alias *) xmalloc (sizeof (struct alias) + fromlen + tolen);
422:
423: newp->fromname = mempcpy (newp->toname, toname, tolen);
424: memcpy (newp->fromname, fromname, fromlen);
425: newp->module = NULL;
426:
427: inserted = (void **) tsearch (newp, &aliases, alias_compare);
428: if (inserted == NULL)
429: error (EXIT_FAILURE, errno, gettext ("while inserting in search tree"));
430: if (*inserted != newp)
431:
432: free (newp);
433: else
434: {
435: newp->froment = strtabadd (strtab, newp->fromname, fromlen);
436: newp->toent = strtabadd (strtab, newp->toname, tolen);
437: }
438: }
439:
440:
441:
442: static void
443: add_alias (char *rp)
444: {
445:
446:
447: char *from;
448: char *to;
449: char *wp;
450:
451: while (isspace (*rp))
452: ++rp;
453: from = wp = rp;
454: while (*rp != '\0' && !isspace (*rp))
455: *wp++ = toupper (*rp++);
456: if (*rp == '\0')
457:
458: return;
459: *wp++ = '\0';
460: to = ++rp;
461: while (isspace (*rp))
462: ++rp;
463: while (*rp != '\0' && !isspace (*rp))
464: *wp++ = toupper (*rp++);
465: if (to == wp)
466:
467: return;
468: *wp++ = '\0';
469:
470: assert (strlen (from) + 1 == (size_t) (to - from));
471: assert (strlen (to) + 1 == (size_t) (wp - to));
472:
473: new_alias (from, to - from, to, wp - to);
474: }
475:
476:
477: static void
478: append_alias (const void *nodep, VISIT value, int level)
479: {
480: if (value != leaf && value != postorder)
481: return;
482:
483: if (nalias_list_max == nalias_list)
484: {
485: nalias_list_max += 50;
486: alias_list = (struct alias **) xrealloc (alias_list,
487: (nalias_list_max
488: * sizeof (struct alias *)));
489: }
490:
491: alias_list[nalias_list++] = *(struct alias **) nodep;
492: }
493:
494:
495: static void
496: get_aliases (void)
497: {
498: twalk (aliases, append_alias);
499: }
500:
501:
502: static int
503: module_compare (const void *p1, const void *p2)
504: {
505: const struct module *m1 = (const struct module *) p1;
506: const struct module *m2 = (const struct module *) p2;
507: int result;
508:
509: result = strcmp (m1->fromname, m2->fromname);
510: if (result == 0)
511: result = strcmp (m1->toname, m2->toname);
512:
513: return result;
514: }
515:
516:
517:
518: static void
519: new_module (const char *fromname, size_t fromlen, const char *toname,
520: size_t tolen, const char *directory,
521: const char *filename, size_t filelen, int cost, size_t need_ext)
522: {
523: struct module *new_module;
524: size_t dirlen = strlen (directory) + 1;
525: char *tmp;
526: void **inserted;
527:
528: new_module = (struct module *) xmalloc (sizeof (struct module)
529: + fromlen + tolen + filelen
530: + need_ext);
531:
532: new_module->fromname = mempcpy (new_module->toname, toname, tolen);
533:
534: new_module->filename = mempcpy (new_module->fromname, fromname, fromlen);
535:
536: new_module->cost = cost;
537: new_module->next = NULL;
538:
539: tmp = mempcpy (new_module->filename, filename, filelen);
540: if (need_ext)
541: {
542: memcpy (tmp - 1, gconv_module_ext, need_ext + 1);
543: filelen += need_ext;
544: }
545: new_module->directory = directory;
546:
547:
548: inserted = (void **) tsearch (new_module, &modules, module_compare);
549: if (inserted == NULL)
550: error (EXIT_FAILURE, errno, "while inserting in search tree");
551: if (*inserted != new_module)
552: free (new_module);
553: else
554: {
555: new_module->fromname_strent = strtabadd (strtab, new_module->fromname,
556: fromlen);
557: new_module->toname_strent = strtabadd (strtab, new_module->toname,
558: tolen);
559: new_module->filename_strent = strtabadd (strtab, new_module->filename,
560: filelen);
561: new_module->directory_strent = strtabadd (strtab, directory, dirlen);
562: }
563: }
564:
565:
566:
567: static void
568: internal_function
569: add_module (char *rp, const char *directory)
570: {
571:
572:
573:
574:
575:
576:
577: char *from;
578: char *to;
579: char *module;
580: char *wp;
581: int need_ext;
582: int cost;
583: