Intial commit
[profile/ivi/w3m.git] / libwc / ucs.c
1
2 #ifdef USE_UNICODE
3
4 #include <stdlib.h>
5 #include "wc.h"
6 #include "ucs.h"
7 #include "search.h"
8 #include "big5.h"
9 #include "hkscs.h"
10 #include "sjis.h"
11 #include "johab.h"
12 #include "gbk.h"
13 #include "gb18030.h"
14 #include "uhc.h"
15 #include "viet.h"
16 #include "wtf.h"
17
18 #include "ucs.map"
19
20 #include "map/ucs_wide.map"
21 #include "map/ucs_combining.map"
22 #include "map/ucs_precompose.map"
23 #include "map/ucs_hangul.map"
24 #include "map/ucs_fullwidth.map"
25
26 #define MAX_TAG_MAP 0x100
27 static int n_tag_map = 0;
28 static char *tag_map[ MAX_TAG_MAP ];
29
30 wc_table *
31 wc_get_ucs_table(wc_ccs ccs)
32 {
33     int f = WC_CCS_INDEX(ccs);
34
35     switch (WC_CCS_TYPE(ccs)) {
36     case WC_CCS_A_CS94:
37         if (f < WC_F_ISO_BASE || f > WC_F_CS94_END)
38             return NULL;
39         return &ucs_cs94_table[f - WC_F_ISO_BASE];
40     case WC_CCS_A_CS94W:
41         if (f < WC_F_ISO_BASE || f > WC_F_CS94W_END)
42             return NULL;
43         return &ucs_cs94w_table[f - WC_F_ISO_BASE];
44     case WC_CCS_A_CS96:
45         if (f < WC_F_ISO_BASE || f > WC_F_CS96_END)
46             return NULL;
47         return &ucs_cs96_table[f - WC_F_ISO_BASE];
48     case WC_CCS_A_CS96W:
49         if (f < WC_F_ISO_BASE || f > WC_F_CS96W_END)
50             return NULL;
51         return &ucs_cs96w_table[f - WC_F_ISO_BASE];
52     case WC_CCS_A_CS942:
53         if (f < WC_F_ISO_BASE || f > WC_F_CS942_END)
54             return NULL;
55         return &ucs_cs942_table[f - WC_F_ISO_BASE];
56     case WC_CCS_A_PCS:
57         if (f < WC_F_PCS_BASE || f > WC_F_PCS_END)
58             return NULL;
59         return &ucs_pcs_table[f - WC_F_PCS_BASE];
60     case WC_CCS_A_PCSW:
61         if (f < WC_F_PCS_BASE || f > WC_F_PCSW_END)
62             return NULL;
63         return &ucs_pcsw_table[f - WC_F_PCS_BASE];
64     default:
65         return NULL;
66     }
67 }
68
69 wc_wchar_t
70 wc_ucs_to_any(wc_uint32 ucs, wc_table *t)
71 {
72     wc_wchar_t cc;
73     wc_map *map;
74
75     if (t && t->map && ucs && ucs <= WC_C_UCS2_END) {
76         map = wc_map_search((wc_uint16)ucs, t->map, t->n);
77         if (map)
78             return t->conv(t->ccs, map->code2);
79     }
80     if (t && (ucs & ~0xFFFF) == WC_C_UCS4_PLANE2) {
81         if (t->ccs == WC_CCS_JIS_X_0213_1)
82             map = wc_map_search((wc_uint16)(ucs & 0xffff),
83                 ucs_p2_jisx02131_map, N_ucs_p2_jisx02131_map);
84         else if (t->ccs == WC_CCS_JIS_X_0213_2)
85             map = wc_map_search((wc_uint16)(ucs & 0xffff),
86                 ucs_p2_jisx02132_map, N_ucs_p2_jisx02132_map);
87         else if (t->ccs == WC_CCS_HKSCS ||
88                  t->ccs == WC_CCS_HKSCS_1 || t->ccs == WC_CCS_HKSCS_2)
89             map = wc_map_search((wc_uint16)(ucs & 0xffff),
90                 ucs_p2_hkscs_map, N_ucs_p2_hkscs_map);
91         else
92             map = NULL;
93         if (map)
94             return t->conv(t->ccs, map->code2);
95     }
96     cc.ccs = WC_CCS_UNKNOWN;
97     return cc;
98 }
99
100 wc_uint32
101 wc_any_to_ucs(wc_wchar_t cc)
102 {
103     int f;
104     wc_uint16 *map = NULL;
105     wc_map *map2;
106
107     f = WC_CCS_INDEX(cc.ccs);
108     switch (WC_CCS_TYPE(cc.ccs)) {
109     case WC_CCS_A_CS94:
110         if (f < WC_F_ISO_BASE || f > WC_F_CS94_END)
111             return WC_C_UCS4_ERROR;
112         map = cs94_ucs_map[f - WC_F_ISO_BASE];
113         cc.code &= 0x7f;
114         break;
115     case WC_CCS_A_CS94W:
116         if (cc.ccs == WC_CCS_GB_2312 && WcOption.use_gb12345_map) {
117             cc.ccs = WC_CCS_GB_12345;
118             return wc_any_to_ucs(cc);
119         } else if (cc.ccs == WC_CCS_JIS_X_0213_1) {
120             map2 = wc_map_search((wc_uint16)(cc.code & 0x7f7f),
121                 jisx02131_ucs_p2_map, N_jisx02131_ucs_p2_map);
122             if (map2)
123                 return map2->code2 | WC_C_UCS4_PLANE2;
124         } else if (cc.ccs == WC_CCS_JIS_X_0213_2) {
125             map2 = wc_map_search((wc_uint16)(cc.code & 0x7f7f),
126                 jisx02132_ucs_p2_map, N_jisx02132_ucs_p2_map);
127             if (map2)
128                 return map2->code2 | WC_C_UCS4_PLANE2;
129         }
130         if (f < WC_F_ISO_BASE || f > WC_F_CS94W_END)
131             return 0;
132         map = cs94w_ucs_map[f - WC_F_ISO_BASE];
133         cc.code = WC_CS94W_N(cc.code);
134         break;
135     case WC_CCS_A_CS96:
136         if (f < WC_F_ISO_BASE || f > WC_F_CS96_END)
137             return WC_C_UCS4_ERROR;
138         map = cs96_ucs_map[f - WC_F_ISO_BASE];
139         cc.code &= 0x7f;
140         break;
141     case WC_CCS_A_CS96W:
142         if (f < WC_F_ISO_BASE || f > WC_F_CS96W_END)
143             return WC_C_UCS4_ERROR;
144         map = cs96w_ucs_map[f - WC_F_ISO_BASE];
145         cc.code = WC_CS96W_N(cc.code);
146         break;
147     case WC_CCS_A_CS942:
148         if (f < WC_F_ISO_BASE || f > WC_F_CS942_END)
149             return WC_C_UCS4_ERROR;
150         map = cs942_ucs_map[f - WC_F_ISO_BASE];
151         cc.code &= 0x7f;
152         break;
153     case WC_CCS_A_PCS:
154         if (f < WC_F_PCS_BASE || f > WC_F_PCS_END)
155             return WC_C_UCS4_ERROR;
156         switch (cc.ccs) {
157         case WC_CCS_CP1258_2:
158             map2 = wc_map_search((wc_uint16)cc.code,
159                 cp12582_ucs_map, N_cp12582_ucs_map);
160             if (map2)
161                 return map2->code2;
162             return WC_C_UCS4_ERROR;
163         case WC_CCS_TCVN_5712_3:
164             return wc_any_to_ucs(wc_tcvn57123_to_tcvn5712(cc));
165         case WC_CCS_GBK_80:
166             return WC_C_UCS2_EURO;
167         }
168         map = pcs_ucs_map[f - WC_F_PCS_BASE];
169         cc.code &= 0x7f;
170         break;
171     case WC_CCS_A_PCSW:
172         if (f < WC_F_PCS_BASE || f > WC_F_PCSW_END)
173             return WC_C_UCS4_ERROR;
174         map = pcsw_ucs_map[f - WC_F_PCS_BASE];
175         switch (cc.ccs) {
176         case WC_CCS_BIG5:
177             cc.code = WC_BIG5_N(cc.code);
178             break;
179         case WC_CCS_BIG5_2:
180             cc.code = WC_CS94W_N(cc.code) + WC_C_BIG5_2_BASE;
181             break;
182         case WC_CCS_HKSCS_1:
183         case WC_CCS_HKSCS_2:
184             cc = wc_cs128w_to_hkscs(cc);
185         case WC_CCS_HKSCS:
186             map2 = wc_map_search((wc_uint16)cc.code,
187                 hkscs_ucs_p2_map, N_hkscs_ucs_p2_map);
188             if (map2)
189                 return map2->code2 | WC_C_UCS4_PLANE2;
190             cc.code = wc_hkscs_to_N(cc.code);
191             break;
192         case WC_CCS_JOHAB:
193             return wc_any_to_ucs(wc_johab_to_cs128w(cc));
194         case WC_CCS_JOHAB_1:
195             return WC_CS94x128_N(cc.code) + WC_C_UCS2_HANGUL;
196         case WC_CCS_JOHAB_2:
197             cc.code = WC_CS128W_N(cc.code);
198             cc.code = WC_N_JOHAB2(cc.code);
199             map2 = wc_map_search((wc_uint16)cc.code,
200                 johab2_ucs_map, N_johab2_ucs_map);
201             if (map2)
202                 return map2->code2;
203             return WC_C_UCS4_ERROR;
204         case WC_CCS_JOHAB_3:
205             if ((cc.code & 0x7f7f) < 0x2121)
206                 return WC_C_UCS4_ERROR;
207         case WC_CCS_SJIS_EXT:
208             return wc_any_to_ucs(wc_sjis_ext_to_cs94w(cc));
209         case WC_CCS_SJIS_EXT_1:
210             cc.code = wc_sjis_ext1_to_N(cc.code);
211             if (cc.code == WC_C_SJIS_ERROR)
212                 return WC_C_UCS4_ERROR;
213             break;
214         case WC_CCS_SJIS_EXT_2:
215             cc.code = wc_sjis_ext2_to_N(cc.code);
216             if (cc.code == WC_C_SJIS_ERROR)
217                 return WC_C_UCS4_ERROR;
218             break;
219         case WC_CCS_GBK_1:
220         case WC_CCS_GBK_2:
221             cc = wc_cs128w_to_gbk(cc);
222         case WC_CCS_GBK:
223             cc.code = wc_gbk_to_N(cc.code);
224             break;
225         case WC_CCS_GBK_EXT:
226         case WC_CCS_GBK_EXT_1:
227         case WC_CCS_GBK_EXT_2:
228             return wc_gb18030_to_ucs(cc);
229         case WC_CCS_UHC_1:
230         case WC_CCS_UHC_2:
231             cc = wc_cs128w_to_uhc(cc);
232         case WC_CCS_UHC:
233             if (cc.code > WC_C_UHC_END)
234                 return WC_C_UCS4_ERROR;
235             cc.code = wc_uhc_to_N(cc.code);
236             break;
237         default:
238             cc.code = WC_CS94W_N(cc.code);
239             break;
240         }
241         break;
242     case WC_CCS_A_WCS16:
243         switch (WC_CCS_SET(cc.ccs)) {
244         case WC_CCS_UCS2:
245             return cc.code;
246         }
247         return WC_C_UCS4_ERROR;
248     case WC_CCS_A_WCS32:
249         switch (WC_CCS_SET(cc.ccs)) {
250         case WC_CCS_UCS4:
251             return cc.code;
252         case WC_CCS_UCS_TAG:
253             return wc_ucs_tag_to_ucs(cc.code);
254         case WC_CCS_GB18030:
255             return wc_gb18030_to_ucs(cc);
256         }
257         return WC_C_UCS4_ERROR;
258     case WC_CCS_A_UNKNOWN:
259         if (cc.ccs == WC_CCS_C1)
260             return (cc.code | 0x80);
261     default:
262         return WC_C_UCS4_ERROR;
263     }
264     if (map == NULL)
265         return WC_C_UCS4_ERROR;
266     cc.code = map[cc.code];
267     return cc.code ? cc.code : WC_C_UCS4_ERROR;
268 }
269
270 wc_wchar_t
271 wc_any_to_any(wc_wchar_t cc, wc_table *t)
272 {
273     wc_ccs is_wide = WC_CCS_IS_WIDE(cc.ccs);
274     wc_uint32 ucs = wc_any_to_ucs(cc);
275
276     if (ucs != WC_C_UCS4_ERROR) {
277         cc = wc_ucs_to_any(ucs, t);
278         if (!WC_CCS_IS_UNKNOWN(cc.ccs))
279             return cc;
280
281         ucs = wc_ucs_to_fullwidth(ucs);
282         if (ucs != WC_C_UCS4_ERROR) {
283             cc = wc_ucs_to_any(ucs, t);
284             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
285                 return cc;
286         }
287     }
288     cc.ccs = is_wide ? WC_CCS_UNKNOWN_W : WC_CCS_UNKNOWN;
289     return cc;
290 }
291
292 wc_wchar_t
293 wc_ucs_to_any_list(wc_uint32 ucs, wc_table **tlist)
294 {
295     wc_wchar_t cc;
296     wc_table **t;
297
298     if (tlist != NULL) {
299         for (t = tlist; *t != NULL; t++) {
300             if ((*t)->map == NULL)
301                 continue;
302             cc = wc_ucs_to_any(ucs, *t);
303             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
304                 return cc;
305         }
306     }
307     cc.ccs = WC_CCS_UNKNOWN;
308     return cc;
309 }
310
311 wc_wchar_t
312 wc_any_to_any_ces(wc_wchar_t cc, wc_status *st)
313 {
314     wc_uint32 ucs = wc_any_to_ucs(cc);
315     wc_ccs is_wide = WC_CCS_IS_WIDE(cc.ccs);
316
317     if (ucs < 0x80) {
318         cc.ccs = WC_CCS_US_ASCII;
319         cc.code = ucs;
320         return cc;
321     }
322     if (ucs != WC_C_UCS4_ERROR) {
323         if (st->ces_info->id & WC_CES_T_UTF) {
324             cc.ccs = wc_ucs_to_ccs(ucs);
325             cc.code = ucs;
326             return cc;
327         } else if (st->ces_info->id == WC_CES_JOHAB) {
328             cc = wc_ucs_to_johab(ucs);
329             if (WC_CCS_IS_UNKNOWN(cc.ccs))
330                 cc.ccs = is_wide ? WC_CCS_UNKNOWN_W : WC_CCS_UNKNOWN;
331             return cc;
332         }
333         cc = wc_ucs_to_any_list(ucs, is_wide ? st->tlistw : st->tlist);
334         if (!WC_CCS_IS_UNKNOWN(cc.ccs))
335             return cc;
336         if (! WcOption.fix_width_conv) {
337             cc = wc_ucs_to_any_list(ucs, is_wide ? st->tlist : st->tlistw);
338             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
339                 return cc;
340         }
341         if (st->ces_info->id == WC_CES_GB18030) {
342             cc = wc_ucs_to_gb18030(ucs);
343             if (WC_CCS_IS_UNKNOWN(cc.ccs))
344                 cc.ccs = is_wide ? WC_CCS_UNKNOWN_W : WC_CCS_UNKNOWN;
345             return cc;
346         }
347         if (ucs == WC_C_UCS2_NBSP) {    /* NBSP -> SP */
348             cc.ccs = WC_CCS_US_ASCII;
349             cc.code = 0x20;
350             return cc;
351         }
352         if (st->ces_info->id & (WC_CES_T_ISO_8859|WC_CES_T_EUC) &&
353             0x80 <= ucs && ucs <= 0x9F) {
354             cc.ccs = WC_CCS_C1;
355             cc.code = ucs;
356             return cc;
357         }
358
359         ucs = wc_ucs_to_fullwidth(ucs);
360         if (ucs != WC_C_UCS4_ERROR) {
361             cc = wc_ucs_to_any_list(ucs, is_wide ? st->tlistw : st->tlist);
362             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
363                 return cc;
364             if (! WcOption.fix_width_conv) {
365                 cc = wc_ucs_to_any_list(ucs, is_wide ? st->tlist : st->tlistw);
366                 if (!WC_CCS_IS_UNKNOWN(cc.ccs))
367                     return cc;
368             }
369         }
370     }
371     cc.ccs = is_wide ? WC_CCS_UNKNOWN_W : WC_CCS_UNKNOWN;
372     return cc;
373 }
374
375 wc_wchar_t
376 wc_any_to_iso2022(wc_wchar_t cc, wc_status *st)
377 {
378     wc_uint32 ucs = wc_any_to_ucs(cc);
379     wc_ccs is_wide = WC_CCS_IS_WIDE(cc.ccs);
380
381     if (ucs < 0x80) {
382         cc.ccs = WC_CCS_US_ASCII;
383         cc.code = ucs;
384         return cc;
385     }
386     if (ucs != WC_C_UCS4_ERROR) {
387         cc = wc_ucs_to_any_list(ucs, is_wide ? st->tlistw : st->tlist);
388         if (!WC_CCS_IS_UNKNOWN(cc.ccs))
389             return cc;
390         if (! WcOption.strict_iso2022) {
391             cc = (is_wide) ? wc_ucs_to_iso2022w(ucs) : wc_ucs_to_iso2022(ucs);
392             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
393                 return cc;
394         }
395         if (! WcOption.fix_width_conv) {
396             cc = wc_ucs_to_any_list(ucs, is_wide ? st->tlist : st->tlistw);
397             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
398                 return cc;
399             if (! WcOption.strict_iso2022) {
400                 cc = (is_wide) ? wc_ucs_to_iso2022(ucs) : wc_ucs_to_iso2022w(ucs);
401                 if (!WC_CCS_IS_UNKNOWN(cc.ccs))
402                     return cc;
403             }
404         }
405         if (ucs == WC_C_UCS2_NBSP) {    /* NBSP -> SP */
406            cc.ccs = WC_CCS_US_ASCII;
407            cc.code = 0x20;
408            return cc;
409         }
410
411         ucs = wc_ucs_to_fullwidth(ucs);
412         if (ucs != WC_C_UCS4_ERROR) {
413             cc = wc_ucs_to_any_list(ucs, is_wide ? st->tlistw : st->tlist);
414             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
415                 return cc;
416             if (! WcOption.strict_iso2022) {
417                 cc = (is_wide) ? wc_ucs_to_iso2022w(ucs) : wc_ucs_to_iso2022(ucs);
418                 if (!WC_CCS_IS_UNKNOWN(cc.ccs))
419                     return cc;
420             }
421             if (! WcOption.fix_width_conv) {
422                 cc = wc_ucs_to_any_list(ucs, is_wide ? st->tlist : st->tlistw);
423                 if (!WC_CCS_IS_UNKNOWN(cc.ccs))
424                     return cc;
425                 if (! WcOption.strict_iso2022) {
426                     cc = (is_wide) ? wc_ucs_to_iso2022(ucs) : wc_ucs_to_iso2022w(ucs);
427                     if (!WC_CCS_IS_UNKNOWN(cc.ccs))
428                         return cc;
429                 }
430             }
431         }
432         if (ucs == WC_C_UCS2_NBSP) {    /* NBSP -> SP */
433            cc.ccs = WC_CCS_US_ASCII;
434            cc.code = 0x20;
435            return cc;
436         }
437     }
438     cc.ccs = is_wide ? WC_CCS_UNKNOWN_W : WC_CCS_UNKNOWN;
439     return cc;
440 }
441
442 wc_wchar_t
443 wc_ucs_to_iso2022(wc_uint32 ucs)
444 {
445     wc_table *t;
446     wc_wchar_t cc;
447     int f;
448
449     if (ucs <= WC_C_UCS2_END) {
450         for (f = 0; f <= WC_F_CS96_END - WC_F_ISO_BASE; f++) {
451             t = &ucs_cs96_table[f];
452             if (t->map == NULL)
453                 continue;
454             cc = wc_ucs_to_any((wc_uint16)ucs, t);
455             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
456                 return cc;
457         }
458         for (f = 0; f <= WC_F_CS94_END - WC_F_ISO_BASE; f++) {
459             t = &ucs_cs94_table[f];
460             if (t->map == NULL)
461                 continue;
462             cc = wc_ucs_to_any((wc_uint16)ucs, t);
463             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
464                 return cc;
465         }
466         for (f = 0; f <= WC_F_CS942_END - WC_F_ISO_BASE; f++) {
467             t = &ucs_cs942_table[f];
468             if (t->map == NULL)
469                 continue;
470             cc = wc_ucs_to_any((wc_uint16)ucs, t);
471             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
472                 return cc;
473         }
474     }
475     cc.ccs = WC_CCS_UNKNOWN;
476     return cc;
477 }
478
479 wc_wchar_t
480 wc_ucs_to_iso2022w(wc_uint32 ucs)
481 {
482     wc_table *t;
483     wc_wchar_t cc;
484     int f;
485
486     if (ucs <= WC_C_UCS2_END) {
487         for (f = 0; f <= WC_F_CS94W_END - WC_F_ISO_BASE; f++) {
488             t = &ucs_cs94w_table[f];
489             if (t->map == NULL)
490                 continue;
491             cc = wc_ucs_to_any((wc_uint16)ucs, t);
492             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
493                 return cc;
494         }
495         for (f = 0; f <= WC_F_CS96W_END - WC_F_ISO_BASE; f++) {
496             t = &ucs_cs96w_table[f];
497             if (t->map == NULL)
498                 continue;
499             cc = wc_ucs_to_any((wc_uint16)ucs, t);
500             if (!WC_CCS_IS_UNKNOWN(cc.ccs))
501                 return cc;
502         }
503     }
504     cc.ccs = WC_CCS_UNKNOWN_W;
505     return cc;
506 }
507
508 wc_ccs
509 wc_ucs_to_ccs(wc_uint32 ucs)
510 {
511     if (0x80 <= ucs && ucs <= 0x9F)
512         return WC_CCS_C1;
513     return ((ucs <= WC_C_UCS2_END) ? WC_CCS_UCS2 : WC_CCS_UCS4)
514         | (wc_is_ucs_wide(ucs) ? WC_CCS_A_WIDE : 0)
515         | (wc_is_ucs_combining(ucs) ? WC_CCS_A_COMB : 0);
516 }
517
518 wc_bool
519 wc_is_ucs_wide(wc_uint32 ucs)
520 {
521     if (ucs <= WC_C_UCS2_END)
522         return (wc_map_range_search((wc_uint16)ucs,
523                 ucs_wide_map, N_ucs_wide_map) != NULL);
524     else
525         return ((ucs & ~0xFFFF) == WC_C_UCS4_PLANE2 ||
526                 (ucs & ~0xFFFF) == WC_C_UCS4_PLANE3);
527 }
528
529 wc_bool
530 wc_is_ucs_combining(wc_uint32 ucs)
531 {
532     return (WcOption.use_combining && ucs <= WC_C_UCS2_END &&
533         wc_map_range_search((wc_uint16)ucs,
534         ucs_combining_map, N_ucs_combining_map) != NULL);
535 }
536
537 wc_bool
538 wc_is_ucs_hangul(wc_uint32 ucs)
539 {
540     return (ucs <= WC_C_UCS2_END &&
541         wc_map_range_search((wc_uint16)ucs,
542         ucs_hangul_map, N_ucs_hangul_map) != NULL);
543 }
544
545 wc_uint32
546 wc_ucs_precompose(wc_uint32 ucs1, wc_uint32 ucs2)
547 {
548     wc_map3 *map;
549
550     if (WcOption.use_combining &&
551         ucs1 <= WC_C_UCS2_END && ucs2 <= WC_C_UCS2_END &&
552         (map = wc_map3_search((wc_uint16)ucs1, (wc_uint16)ucs2,
553         ucs_precompose_map, N_ucs_precompose_map)) != NULL)
554         return map->code3;
555     return WC_C_UCS4_ERROR;
556 }
557
558 wc_uint32
559 wc_ucs_to_fullwidth(wc_uint32 ucs)
560 {
561     wc_map *map;
562
563     if (ucs <= WC_C_UCS2_END &&
564         (map = wc_map_search((wc_uint16)ucs,
565         ucs_fullwidth_map, N_ucs_fullwidth_map)) != NULL)
566         return map->code2;
567     return WC_C_UCS4_ERROR;
568 }
569
570 int
571 wc_ucs_put_tag(char *p)
572 {
573     int i;
574
575     if (p == NULL || *p == '\0')
576         return 0;
577     for (i = 1; i <= n_tag_map; i++) {
578         if (!strcasecmp(p, tag_map[i]))
579             return i;
580     }
581     n_tag_map++;
582     if (n_tag_map == MAX_TAG_MAP)
583         return 0;
584     tag_map[n_tag_map] = p;
585     return n_tag_map;
586 }
587
588 char *
589 wc_ucs_get_tag(int ntag)
590 {
591     if (ntag == 0 || ntag > n_tag_map)
592         return NULL;
593     return tag_map[ntag];
594 }
595
596 void
597 wtf_push_ucs(Str os, wc_uint32 ucs, wc_status *st)
598 {
599     wc_ccs ccs;
600
601     if (ucs >= WC_C_LANGUAGE_TAG0 && ucs <= WC_C_CANCEL_TAG) {
602         if (! WcOption.use_language_tag)
603             return;
604         if (ucs == WC_C_LANGUAGE_TAG)
605             st->tag = Strnew_size(4);
606         else if (ucs == WC_C_CANCEL_TAG) {
607             st->tag = NULL;
608             st->ntag = 0;
609         }  else if (st->tag && ucs >= WC_C_TAG_SPACE)
610             Strcat_char(st->tag, (char)(ucs & 0x7f));
611         return;
612     }
613     if (st->tag) {
614         st->ntag = wc_ucs_put_tag(st->tag->ptr);
615         st->tag = NULL;
616     }
617     if (ucs < 0x80) {
618         if (st->ntag)
619             wtf_push(os, WC_CCS_UCS_TAG,  wc_ucs_to_ucs_tag(ucs, st->ntag));
620         else
621             Strcat_char(os, (char)ucs);
622     } else {
623         ccs = wc_ucs_to_ccs(ucs);
624         if (st->ntag && ucs <= WC_C_UNICODE_END) {
625             ccs = wc_ccs_ucs_to_ccs_ucs_tag(ccs);
626             ucs = wc_ucs_to_ucs_tag(ucs, st->ntag);
627         }
628         wtf_push(os, ccs, ucs);
629     }
630 }
631
632 #endif