1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22: #include <assert.h>
23: #include <limits.h>
24: #include <search.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <sys/param.h>
28: #include <bits/libc-lock.h>
29: #include <locale/localeinfo.h>
30:
31: #include <dlfcn.h>
32: #include <gconv_int.h>
33: #include <sysdep.h>
34:
35:
36:
37:
38: void *__gconv_alias_db;
39:
40:
41: struct gconv_module *__gconv_modules_db;
42:
43:
44: __libc_lock_define_initialized (, __gconv_lock)
45:
46:
47:
48: struct gconv_module *
49: __gconv_get_modules_db (void)
50: {
51: return __gconv_modules_db;
52: }
53:
54: void *
55: __gconv_get_alias_db (void)
56: {
57: return __gconv_alias_db;
58: }
59:
60:
61:
62: int
63: __gconv_alias_compare (const void *p1, const void *p2)
64: {
65: const struct gconv_alias *s1 = (const struct gconv_alias *) p1;
66: const struct gconv_alias *s2 = (const struct gconv_alias *) p2;
67: return strcmp (s1->fromname, s2->fromname);
68: }
69:
70:
71:
72:
73:
74: struct derivation_step
75: {
76: const char *result_set;
77: size_t result_set_len;
78: int cost_lo;
79: int cost_hi;
80: struct gconv_module *code;
81: struct derivation_step *last;
82: struct derivation_step *next;
83: };
84:
85: #define NEW_STEP(result, hi, lo, module, last_mod) \
86: ({ struct derivation_step *newp = alloca (sizeof (struct derivation_step)); \
87: newp->result_set = result; \
88: newp->result_set_len = strlen (result); \
89: newp->cost_hi = hi; \
90: newp->cost_lo = lo; \
91: newp->code = module; \
92: newp->last = last_mod; \
93: newp->next = NULL; \
94: newp; })
95:
96:
97:
98:
99: struct known_derivation
100: {
101: const char *from;
102: const char *to;
103: struct __gconv_step *steps;
104: size_t nsteps;
105: };
106:
107:
108: static int
109: derivation_compare (const void *p1, const void *p2)
110: {
111: const struct known_derivation *s1 = (const struct known_derivation *) p1;
112: const struct known_derivation *s2 = (const struct known_derivation *) p2;
113: int result;
114:
115: result = strcmp (s1->from, s2->from);
116: if (result == 0)
117: result = strcmp (s1->to, s2->to);
118: return result;
119: }
120:
121:
122: static void *known_derivations;
123:
124:
125: static int
126: internal_function
127: derivation_lookup (const char *fromset, const char *toset,
128: struct __gconv_step **handle, size_t *nsteps)
129: {
130: struct known_derivation key = { fromset, toset, NULL, 0 };
131: struct known_derivation **result;
132:
133: result = __tfind (&key, &known_derivations, derivation_compare);
134:
135: if (result == NULL)
136: return __GCONV_NOCONV;
137:
138: *handle = (*result)->steps;
139: *nsteps = (*result)->nsteps;
140:
141:
142:
143: return __GCONV_OK;
144: }
145:
146:
147: static void
148: internal_function
149: add_derivation (const char *fromset, const char *toset,
150: struct __gconv_step *handle, size_t nsteps)
151: {
152: struct known_derivation *new_deriv;
153: size_t fromset_len = strlen (fromset) + 1;
154: size_t toset_len = strlen (toset) + 1;
155:
156: new_deriv = (struct known_derivation *)
157: malloc (sizeof (struct known_derivation) + fromset_len + toset_len);
158: if (new_deriv != NULL)
159: {
160: new_deriv->from = (char *) (new_deriv + 1);
161: new_deriv->to = memcpy (__mempcpy (new_deriv + 1, fromset, fromset_len),
162: toset, toset_len);
163:
164: new_deriv->steps = handle;
165: new_deriv->nsteps = nsteps;
166:
167: if (__tsearch (new_deriv, &known_derivations, derivation_compare)
168: == NULL)
169:
170: free (new_deriv);
171: }
172:
173:
174:
175: }
176:
177: static void __libc_freeres_fn_section
178: free_derivation (void *p)
179: {
180: struct known_derivation *deriv = (struct known_derivation *) p;
181: size_t cnt;
182:
183: for (cnt = 0; cnt < deriv->nsteps; ++cnt)
184: if (deriv->steps[cnt].__counter > 0
185: && deriv->steps[cnt].__end_fct != NULL)
186: {
187: assert (deriv->steps[cnt].__shlib_handle != NULL);
188:
189: __gconv_end_fct end_fct = deriv->steps[cnt].__end_fct;
190: #ifdef PTR_DEMANGLE
191: PTR_DEMANGLE (end_fct);
192: #endif
193: DL_CALL_FCT (end_fct, (&deriv->steps[cnt]));
194: }
195:
196:
197: free ((char *) deriv->steps[0].__from_name);
198: free ((char *) deriv->steps[deriv->nsteps - 1].__to_name);
199:
200: free ((struct __gconv_step *) deriv->steps);
201: free (deriv);
202: }
203:
204:
205:
206: void
207: internal_function
208: __gconv_release_step (struct __gconv_step *step)
209: {
210:
211: if (step->__shlib_handle != NULL && --step->__counter == 0)
212: {
213:
214: if (step->__end_fct != NULL)
215: {
216: assert (step->__shlib_handle != NULL);
217:
218: __gconv_end_fct end_fct = step->__end_fct;
219: #ifdef PTR_DEMANGLE
220: PTR_DEMANGLE (end_fct);
221: #endif
222: DL_CALL_FCT (end_fct, (step));
223: }
224:
225: #ifndef STATIC_GCONV
226:
227: __gconv_release_shlib (step->__shlib_handle);
228: step->__shlib_handle = NULL;
229: #endif
230: }
231: else if (step->__shlib_handle == NULL)
232:
233: assert (step->__end_fct == NULL);
234: }
235:
236: static int
237: internal_function
238: gen_steps (struct derivation_step *best, const char *toset,
239: const char *fromset, struct __gconv_step **handle, size_t *nsteps)
240: {
241: size_t step_cnt = 0;
242: struct __gconv_step *result;
243: struct derivation_step *current;
244: int status = __GCONV_NOMEM;
245:
246:
247: for (current = best; current->last != NULL; current = current->last)
248: ++step_cnt;
249:
250: result = (struct __gconv_step *) malloc (sizeof (struct __gconv_step)
251: * step_cnt);
252: if (result != NULL)
253: {
254: int failed = 0;
255:
256: status = __GCONV_OK;
257: *nsteps = step_cnt;
258: current = best;
259: while (step_cnt-- > 0)
260: {
261: result[step_cnt].__from_name = (step_cnt == 0
262: ? __strdup (fromset)
263: : (char *)current->last->result_set);
264: result[step_cnt].__to_name = (step_cnt + 1 == *nsteps
265: ? __strdup (current->result_set)
266: : result[step_cnt + 1].__from_name);
267:
268: result[step_cnt].__counter = 1;
269: result[step_cnt].__data = NULL;
270:
271: #ifndef STATIC_GCONV
272: if (current->code->module_name[0] == '/')
273: {
274:
275: struct __gconv_loaded_object *shlib_handle =
276: __gconv_find_shlib (current->code->module_name);
277:
278: if (shlib_handle == NULL)
279: {
280: failed = 1;
281: break;
282: }
283:
284: result[step_cnt].__shlib_handle = shlib_handle;
285: result[step_cnt].__modname = shlib_handle->name;
286: result[step_cnt].__fct = shlib_handle->fct;
287: result[step_cnt].__init_fct = shlib_handle->init_fct;
288: result[step_cnt].__end_fct = shlib_handle->end_fct;
289:
290:
291: result[step_cnt].__btowc_fct = NULL;
292:
293:
294: __gconv_init_fct init_fct = result[step_cnt].__init_fct;
295: if (init_fct != NULL)
296: {
297: assert (result[step_cnt].__shlib_handle != NULL);
298:
299: # ifdef PTR_DEMANGLE
300: PTR_DEMANGLE (init_fct);
301: # endif
302: status = DL_CALL_FCT (init_fct, (&result[step_cnt]));
303:
304: if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)
305: {
306: failed = 1;
307:
308: --step_cnt;
309: result[step_cnt].__end_fct = NULL;
310: break;
311: }
312:
313: # ifdef PTR_MANGLE
314: if (result[step_cnt].__btowc_fct != NULL)
315: PTR_MANGLE (result[step_cnt].__btowc_fct);
316: # endif
317: }
318: }
319: else
320: #endif
321:
322: __gconv_get_builtin_trans (current->code->module_name,
323: &result[step_cnt]);
324:
325: current = current->last;
326: }
327:
328: if (__builtin_expect (failed, 0) != 0)
329: {
330:
331: while (++step_cnt < *nsteps)
332: __gconv_release_step (&result[step_cnt]);
333: free (result);
334: *nsteps = 0;
335: *handle = NULL;
336: if (status == __GCONV_OK)
337: status = __GCONV_NOCONV;
338: }
339: else
340: *handle = result;
341: }
342: else
343: {
344: *nsteps = 0;
345: *handle = NULL;
346: }
347:
348: return status;
349: }
350:
351:
352: #ifndef STATIC_GCONV
353: static int
354: internal_function
355: increment_counter (struct __gconv_step *steps, size_t nsteps)
356: {
357:
358: size_t cnt = nsteps;
359: int result = __GCONV_OK;
360:
361: while (cnt-- > 0)
362: {
363: struct __gconv_step *step = &steps[cnt];
364:
365: if (step->__counter++ == 0)
366: {
367:
368: if (step->__modname != NULL)
369: {
370:
371: step->__shlib_handle = __gconv_find_shlib (step->__modname);
372: if (step->__shlib_handle == NULL)
373: {
374:
375:
376: --step->__counter;
377: while (++cnt < nsteps)
378: __gconv_release_step (&steps[cnt]);
379: result = __GCONV_NOCONV;
380: break;
381: }
382:
383:
384:
385: step->__fct = step->__shlib_handle->fct;
386: step->__init_fct = step->__shlib_handle->init_fct;
387: step->__end_fct = step->__shlib_handle->end_fct;
388:
389:
390: step->__btowc_fct = NULL;
391: }
392:
393:
394: __gconv_init_fct init_fct = step->__init_fct;
395: if (init_fct != NULL)
396: {
397: #ifdef PTR_DEMANGLE
398: PTR_DEMANGLE (init_fct);
399: #endif
400: DL_CALL_FCT (init_fct, (step));
401:
402: #ifdef PTR_MANGLE
403: if (step->__btowc_fct != NULL)
404: PTR_MANGLE (step->__btowc_fct);
405: #endif
406: }
407: }
408: }
409: return result;
410: }
411: #endif
412:
413:
414:
415:
416: static int
417: internal_function
418: find_derivation (const char *toset, const char *toset_expand,
419: const char *fromset, const char *fromset_expand,
420: struct __gconv_step **handle, size_t *nsteps)
421: {
422: struct derivation_step *first, *current, **lastp, *solution = NULL;
423: int best_cost_hi = INT_MAX;
424: int best_cost_lo = INT_MAX;
425: int result;
426:
427:
428:
429: result = derivation_lookup (fromset_expand ?: fromset, toset_expand ?: toset,
430: handle, nsteps);
431: if (result == __GCONV_OK)
432: {
433: #ifndef STATIC_GCONV
434: result = increment_counter (*handle, *nsteps);
435: #endif
436: return result;
437: }
438:
439:
440:
441:
442:
443:
444:
445:
446:
447:
448:
449:
450:
451:
452:
453:
454:
455:
456:
457:
458:
459:
460:
461:
462:
463:
464:
465: if (fromset_expand != NULL)
466: {
467: first = NEW_STEP (fromset_expand, 0, 0, NULL, NULL);
468: first->next = NEW_STEP (fromset, 0, 0, NULL, NULL);
469: lastp = &first->next->next;
470: }
471: else
472: {
473: first = NEW_STEP (fromset, 0, 0, NULL, NULL);
474: lastp = &first->next;
475: }
476:
477: for (current = first; current != NULL; current = current->next)
478: {
479:
480:
481:
482:
483:
484:
485:
486:
487:
488:
489: struct gconv_module *node;
490:
491:
492:
493:
494: if (current->cost_hi > best_cost_hi
495: || (current->cost_hi == best_cost_hi
496: && current->cost_lo >= best_cost_lo))
497: continue;
498:
499: node = __gconv_modules_db;
500: while (node != NULL)
501: {
502: int cmpres = strcmp (current->result_set, node->from_string);
503: if (cmpres == 0)
504: {
505:
506:
507: struct gconv_module *runp;
508:
509:
510: runp = node;
511: do
512: {
513: const char *result_set = (strcmp (runp->to_string, "-") == 0
514: ? (toset_expand ?: toset)
515: : runp->to_string);
516: int cost_hi = runp->cost_hi + current->cost_hi;
517: int cost_lo = runp->cost_lo + current->cost_lo;
518: struct derivation_step *step;
519:
520:
521:
522: if (strcmp (result_set, toset) == 0
523: || (toset_expand != NULL
524: && strcmp (result_set, toset_expand) == 0))
525: {
526:
527:
528: for (step = solution; step != NULL; step = step->next)
529: if (strcmp (result_set, step->result_set) == 0)
530: break;
531:
532: if (step == NULL)
533: {
534: step = NEW_STEP (result_set,
535: cost_hi, cost_lo,
536: runp, current);
537: step->next = solution;
538: solution = step;
539: }
540: else if (step->cost_hi > cost_hi
541: || (step->cost_hi == cost_hi
542: && step->cost_lo > cost_lo))
543: {
544:
545:
546: step->code = runp;
547: step->last = current;
548: step->cost_hi = cost_hi;
549: step->cost_lo = cost_lo;
550: }
551:
552:
553: if (cost_hi < best_cost_hi
554: || (cost_hi == best_cost_hi
555: && cost_lo < best_cost_lo))
556: {
557: best_cost_hi = cost_hi;
558: best_cost_lo = cost_lo;
559: }
560: }
561: else if (cost_hi < best_cost_hi
562: || (cost_hi == best_cost_hi
563: && cost_lo < best_cost_lo))
564: {
565:
566:
567: for (step = first; step != NULL; step = step->next)
568: if (strcmp (result_set, step->result_set) == 0)
569: break;
570:
571: if (step == NULL)