PostgreSQL Source Code git master
euc_jp_and_sjis.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * EUC_JP, SJIS and MULE_INTERNAL
4 *
5 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
7 *
8 * IDENTIFICATION
9 * src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/euc_jp_and_sjis.c
10 *
11 *-------------------------------------------------------------------------
12 */
13
14#include "postgres.h"
15#include "fmgr.h"
16#include "mb/pg_wchar.h"
17
18/*
19 * SJIS alternative code.
20 * this code is used if a mapping EUC -> SJIS is not defined.
21 */
22#define PGSJISALTCODE 0x81ac
23#define PGEUCALTCODE 0xa2ae
24
25/*
26 * conversion table between SJIS UDC (IBM kanji) and EUC_JP
27 */
28#include "sjis.map"
29
31 .name = "euc_jp_and_sjis",
32 .version = PG_VERSION
33);
34
41
42/* ----------
43 * conv_proc(
44 * INTEGER, -- source encoding id
45 * INTEGER, -- destination encoding id
46 * CSTRING, -- source string (null terminated C string)
47 * CSTRING, -- destination string (null terminated C string)
48 * INTEGER, -- source string length
49 * BOOL -- if true, don't throw an error if conversion fails
50 * ) returns INTEGER;
51 *
52 * Returns the number of bytes successfully converted.
53 * ----------
54 */
55
56static int sjis2mic(const unsigned char *sjis, unsigned char *p, int len, bool noError);
57static int mic2sjis(const unsigned char *mic, unsigned char *p, int len, bool noError);
58static int euc_jp2mic(const unsigned char *euc, unsigned char *p, int len, bool noError);
59static int mic2euc_jp(const unsigned char *mic, unsigned char *p, int len, bool noError);
60static int euc_jp2sjis(const unsigned char *euc, unsigned char *p, int len, bool noError);
61static int sjis2euc_jp(const unsigned char *sjis, unsigned char *p, int len, bool noError);
62
65{
66 unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
67 unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
68 int len = PG_GETARG_INT32(4);
69 bool noError = PG_GETARG_BOOL(5);
70 int converted;
71
73
74 converted = euc_jp2sjis(src, dest, len, noError);
75
76 PG_RETURN_INT32(converted);
77}
78
81{
82 unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
83 unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
84 int len = PG_GETARG_INT32(4);
85 bool noError = PG_GETARG_BOOL(5);
86 int converted;
87
89
90 converted = sjis2euc_jp(src, dest, len, noError);
91
92 PG_RETURN_INT32(converted);
93}
94
97{
98 unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
99 unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
100 int len = PG_GETARG_INT32(4);
101 bool noError = PG_GETARG_BOOL(5);
102 int converted;
103
105
106 converted = euc_jp2mic(src, dest, len, noError);
107
108 PG_RETURN_INT32(converted);
109}
110
111Datum
113{
114 unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
115 unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
116 int len = PG_GETARG_INT32(4);
117 bool noError = PG_GETARG_BOOL(5);
118 int converted;
119
121
122 converted = mic2euc_jp(src, dest, len, noError);
123
124 PG_RETURN_INT32(converted);
125}
126
127Datum
129{
130 unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
131 unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
132 int len = PG_GETARG_INT32(4);
133 bool noError = PG_GETARG_BOOL(5);
134 int converted;
135
137
138 converted = sjis2mic(src, dest, len, noError);
139
140 PG_RETURN_INT32(converted);
141}
142
143Datum
145{
146 unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
147 unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
148 int len = PG_GETARG_INT32(4);
149 bool noError = PG_GETARG_BOOL(5);
150 int converted;
151
153
154 converted = mic2sjis(src, dest, len, noError);
155
156 PG_RETURN_INT32(converted);
157}
158
159/*
160 * SJIS ---> MIC
161 */
162static int
163sjis2mic(const unsigned char *sjis, unsigned char *p, int len, bool noError)
164{
165 const unsigned char *start = sjis;
166 int c1,
167 c2,
168 i,
169 k,
170 k2;
171
172 while (len > 0)
173 {
174 c1 = *sjis;
175 if (c1 >= 0xa1 && c1 <= 0xdf)
176 {
177 /* JIS X0201 (1 byte kana) */
178 *p++ = LC_JISX0201K;
179 *p++ = c1;
180 sjis++;
181 len--;
182 }
183 else if (IS_HIGHBIT_SET(c1))
184 {
185 /*
186 * JIS X0208, X0212, user defined extended characters
187 */
188 if (len < 2 || !ISSJISHEAD(c1) || !ISSJISTAIL(sjis[1]))
189 {
190 if (noError)
191 break;
192 report_invalid_encoding(PG_SJIS, (const char *) sjis, len);
193 }
194 c2 = sjis[1];
195 k = (c1 << 8) + c2;
196 if (k >= 0xed40 && k < 0xf040)
197 {
198 /* NEC selection IBM kanji */
199 for (i = 0;; i++)
200 {
201 k2 = ibmkanji[i].nec;
202 if (k2 == 0xffff)
203 break;
204 if (k2 == k)
205 {
206 k = ibmkanji[i].sjis;
207 c1 = (k >> 8) & 0xff;
208 c2 = k & 0xff;
209 }
210 }
211 }
212
213 if (k < 0xeb3f)
214 {
215 /* JIS X0208 */
216 *p++ = LC_JISX0208;
217 *p++ = ((c1 & 0x3f) << 1) + 0x9f + (c2 > 0x9e);
218 *p++ = c2 + ((c2 > 0x9e) ? 2 : 0x60) + (c2 < 0x80);
219 }
220 else if ((k >= 0xeb40 && k < 0xf040) || (k >= 0xfc4c && k <= 0xfcfc))
221 {
222 /* NEC selection IBM kanji - Other undecided justice */
223 *p++ = LC_JISX0208;
224 *p++ = PGEUCALTCODE >> 8;
225 *p++ = PGEUCALTCODE & 0xff;
226 }
227 else if (k >= 0xf040 && k < 0xf540)
228 {
229 /*
230 * UDC1 mapping to X0208 85 ku - 94 ku JIS code 0x7521 -
231 * 0x7e7e EUC 0xf5a1 - 0xfefe
232 */
233 *p++ = LC_JISX0208;
234 c1 -= 0x6f;
235 *p++ = ((c1 & 0x3f) << 1) + 0xf3 + (c2 > 0x9e);
236 *p++ = c2 + ((c2 > 0x9e) ? 2 : 0x60) + (c2 < 0x80);
237 }
238 else if (k >= 0xf540 && k < 0xfa40)
239 {
240 /*
241 * UDC2 mapping to X0212 85 ku - 94 ku JIS code 0x7521 -
242 * 0x7e7e EUC 0x8ff5a1 - 0x8ffefe
243 */
244 *p++ = LC_JISX0212;
245 c1 -= 0x74;
246 *p++ = ((c1 & 0x3f) << 1) + 0xf3 + (c2 > 0x9e);
247 *p++ = c2 + ((c2 > 0x9e) ? 2 : 0x60) + (c2 < 0x80);
248 }
249 else if (k >= 0xfa40)
250 {
251 /*
252 * mapping IBM kanji to X0208 and X0212
253 */
254 for (i = 0;; i++)
255 {
256 k2 = ibmkanji[i].sjis;
257 if (k2 == 0xffff)
258 break;
259 if (k2 == k)
260 {
261 k = ibmkanji[i].euc;
262 if (k >= 0x8f0000)
263 {
264 *p++ = LC_JISX0212;
265 *p++ = 0x80 | ((k & 0xff00) >> 8);
266 *p++ = 0x80 | (k & 0xff);
267 }
268 else
269 {
270 *p++ = LC_JISX0208;
271 *p++ = 0x80 | (k >> 8);
272 *p++ = 0x80 | (k & 0xff);
273 }
274 }
275 }
276 }
277 sjis += 2;
278 len -= 2;
279 }
280 else
281 { /* should be ASCII */
282 if (c1 == 0)
283 {
284 if (noError)
285 break;
286 report_invalid_encoding(PG_SJIS, (const char *) sjis, len);
287 }
288 *p++ = c1;
289 sjis++;
290 len--;
291 }
292 }
293 *p = '\0';
294
295 return sjis - start;
296}
297
298/*
299 * MIC ---> SJIS
300 */
301static int
302mic2sjis(const unsigned char *mic, unsigned char *p, int len, bool noError)
303{
304 const unsigned char *start = mic;
305 int c1,
306 c2,
307 k,
308 l;
309
310 while (len > 0)
311 {
312 c1 = *mic;
313 if (!IS_HIGHBIT_SET(c1))
314 {
315 /* ASCII */
316 if (c1 == 0)
317 {
318 if (noError)
319 break;
321 (const char *) mic, len);
322 }
323 *p++ = c1;
324 mic++;
325 len--;
326 continue;
327 }
328 l = pg_encoding_verifymbchar(PG_MULE_INTERNAL, (const char *) mic, len);
329 if (l < 0)
330 {
331 if (noError)
332 break;
334 (const char *) mic, len);
335 }
336 if (c1 == LC_JISX0201K)
337 *p++ = mic[1];
338 else if (c1 == LC_JISX0208)
339 {
340 c1 = mic[1];
341 c2 = mic[2];
342 k = (c1 << 8) | (c2 & 0xff);
343 if (k >= 0xf5a1)
344 {
345 /* UDC1 */
346 c1 -= 0x54;
347 *p++ = ((c1 - 0xa1) >> 1) + ((c1 < 0xdf) ? 0x81 : 0xc1) + 0x6f;
348 }
349 else
350 *p++ = ((c1 - 0xa1) >> 1) + ((c1 < 0xdf) ? 0x81 : 0xc1);
351 *p++ = c2 - ((c1 & 1) ? ((c2 < 0xe0) ? 0x61 : 0x60) : 2);
352 }
353 else if (c1 == LC_JISX0212)
354 {
355 int i,
356 k2;
357
358 c1 = mic[1];
359 c2 = mic[2];
360 k = c1 << 8 | c2;
361 if (k >= 0xf5a1)
362 {
363 /* UDC2 */
364 c1 -= 0x54;
365 *p++ = ((c1 - 0xa1) >> 1) + ((c1 < 0xdf) ? 0x81 : 0xc1) + 0x74;
366 *p++ = c2 - ((c1 & 1) ? ((c2 < 0xe0) ? 0x61 : 0x60) : 2);
367 }
368 else
369 {
370 /* IBM kanji */
371 for (i = 0;; i++)
372 {
373 k2 = ibmkanji[i].euc & 0xffff;
374 if (k2 == 0xffff)
375 {
376 *p++ = PGSJISALTCODE >> 8;
377 *p++ = PGSJISALTCODE & 0xff;
378 break;
379 }
380 if (k2 == k)
381 {
382 k = ibmkanji[i].sjis;
383 *p++ = k >> 8;
384 *p++ = k & 0xff;
385 break;
386 }
387 }
388 }
389 }
390 else
391 {
392 if (noError)
393 break;
395 (const char *) mic, len);
396 }
397 mic += l;
398 len -= l;
399 }
400 *p = '\0';
401
402 return mic - start;
403}
404
405/*
406 * EUC_JP ---> MIC
407 */
408static int
409euc_jp2mic(const unsigned char *euc, unsigned char *p, int len, bool noError)
410{
411 const unsigned char *start = euc;
412 int c1;
413 int l;
414
415 while (len > 0)
416 {
417 c1 = *euc;
418 if (!IS_HIGHBIT_SET(c1))
419 {
420 /* ASCII */
421 if (c1 == 0)
422 {
423 if (noError)
424 break;
426 (const char *) euc, len);
427 }
428 *p++ = c1;
429 euc++;
430 len--;
431 continue;
432 }
433 l = pg_encoding_verifymbchar(PG_EUC_JP, (const char *) euc, len);
434 if (l < 0)
435 {
436 if (noError)
437 break;
439 (const char *) euc, len);
440 }
441 if (c1 == SS2)
442 { /* 1 byte kana? */
443 *p++ = LC_JISX0201K;
444 *p++ = euc[1];
445 }
446 else if (c1 == SS3)
447 { /* JIS X0212 kanji? */
448 *p++ = LC_JISX0212;
449 *p++ = euc[1];
450 *p++ = euc[2];
451 }
452 else
453 { /* kanji? */
454 *p++ = LC_JISX0208;
455 *p++ = c1;
456 *p++ = euc[1];
457 }
458 euc += l;
459 len -= l;
460 }
461 *p = '\0';
462
463 return euc - start;
464}
465
466/*
467 * MIC ---> EUC_JP
468 */
469static int
470mic2euc_jp(const unsigned char *mic, unsigned char *p, int len, bool noError)
471{
472 const unsigned char *start = mic;
473 int c1;
474 int l;
475
476 while (len > 0)
477 {
478 c1 = *mic;
479 if (!IS_HIGHBIT_SET(c1))
480 {
481 /* ASCII */
482 if (c1 == 0)
483 {
484 if (noError)
485 break;
487 (const char *) mic, len);
488 }
489 *p++ = c1;
490 mic++;
491 len--;
492 continue;
493 }
494 l = pg_encoding_verifymbchar(PG_MULE_INTERNAL, (const char *) mic, len);
495 if (l < 0)
496 {
497 if (noError)
498 break;
500 (const char *) mic, len);
501 }
502 if (c1 == LC_JISX0201K)
503 {
504 *p++ = SS2;
505 *p++ = mic[1];
506 }
507 else if (c1 == LC_JISX0212)
508 {
509 *p++ = SS3;
510 *p++ = mic[1];
511 *p++ = mic[2];
512 }
513 else if (c1 == LC_JISX0208)
514 {
515 *p++ = mic[1];
516 *p++ = mic[2];
517 }
518 else
519 {
520 if (noError)
521 break;
523 (const char *) mic, len);
524 }
525 mic += l;
526 len -= l;
527 }
528 *p = '\0';
529
530 return mic - start;
531}
532
533/*
534 * EUC_JP -> SJIS
535 */
536static int
537euc_jp2sjis(const unsigned char *euc, unsigned char *p, int len, bool noError)
538{
539 const unsigned char *start = euc;
540 int c1,
541 c2,
542 k;
543 int l;
544
545 while (len > 0)
546 {
547 c1 = *euc;
548 if (!IS_HIGHBIT_SET(c1))
549 {
550 /* ASCII */
551 if (c1 == 0)
552 {
553 if (noError)
554 break;
556 (const char *) euc, len);
557 }
558 *p++ = c1;
559 euc++;
560 len--;
561 continue;
562 }
563 l = pg_encoding_verifymbchar(PG_EUC_JP, (const char *) euc, len);
564 if (l < 0)
565 {
566 if (noError)
567 break;
569 (const char *) euc, len);
570 }
571 if (c1 == SS2)
572 {
573 /* hankaku kana? */
574 *p++ = euc[1];
575 }
576 else if (c1 == SS3)
577 {
578 /* JIS X0212 kanji? */
579 c1 = euc[1];
580 c2 = euc[2];
581 k = c1 << 8 | c2;
582 if (k >= 0xf5a1)
583 {
584 /* UDC2 */
585 c1 -= 0x54;
586 *p++ = ((c1 - 0xa1) >> 1) + ((c1 < 0xdf) ? 0x81 : 0xc1) + 0x74;
587 *p++ = c2 - ((c1 & 1) ? ((c2 < 0xe0) ? 0x61 : 0x60) : 2);
588 }
589 else
590 {
591 int i,
592 k2;
593
594 /* IBM kanji */
595 for (i = 0;; i++)
596 {
597 k2 = ibmkanji[i].euc & 0xffff;
598 if (k2 == 0xffff)
599 {
600 *p++ = PGSJISALTCODE >> 8;
601 *p++ = PGSJISALTCODE & 0xff;
602 break;
603 }
604 if (k2 == k)
605 {
606 k = ibmkanji[i].sjis;
607 *p++ = k >> 8;
608 *p++ = k & 0xff;
609 break;
610 }
611 }
612 }
613 }
614 else
615 {
616 /* JIS X0208 kanji? */
617 c2 = euc[1];
618 k = (c1 << 8) | (c2 & 0xff);
619 if (k >= 0xf5a1)
620 {
621 /* UDC1 */
622 c1 -= 0x54;
623 *p++ = ((c1 - 0xa1) >> 1) + ((c1 < 0xdf) ? 0x81 : 0xc1) + 0x6f;
624 }
625 else
626 *p++ = ((c1 - 0xa1) >> 1) + ((c1 < 0xdf) ? 0x81 : 0xc1);
627 *p++ = c2 - ((c1 & 1) ? ((c2 < 0xe0) ? 0x61 : 0x60) : 2);
628 }
629 euc += l;
630 len -= l;
631 }
632 *p = '\0';
633
634 return euc - start;
635}
636
637/*
638 * SJIS ---> EUC_JP
639 */
640static int
641sjis2euc_jp(const unsigned char *sjis, unsigned char *p, int len, bool noError)
642{
643 const unsigned char *start = sjis;
644 int c1,
645 c2,
646 i,
647 k,
648 k2;
649 int l;
650
651 while (len > 0)
652 {
653 c1 = *sjis;
654 if (!IS_HIGHBIT_SET(c1))
655 {
656 /* ASCII */
657 if (c1 == 0)
658 {
659 if (noError)
660 break;
662 (const char *) sjis, len);
663 }
664 *p++ = c1;
665 sjis++;
666 len--;
667 continue;
668 }
669 l = pg_encoding_verifymbchar(PG_SJIS, (const char *) sjis, len);
670 if (l < 0)
671 {
672 if (noError)
673 break;
675 (const char *) sjis, len);
676 }
677 if (c1 >= 0xa1 && c1 <= 0xdf)
678 {
679 /* JIS X0201 (1 byte kana) */
680 *p++ = SS2;
681 *p++ = c1;
682 }
683 else
684 {
685 /*
686 * JIS X0208, X0212, user defined extended characters
687 */
688 c2 = sjis[1];
689 k = (c1 << 8) + c2;
690 if (k >= 0xed40 && k < 0xf040)
691 {
692 /* NEC selection IBM kanji */
693 for (i = 0;; i++)
694 {
695 k2 = ibmkanji[i].nec;
696 if (k2 == 0xffff)
697 break;
698 if (k2 == k)
699 {
700 k = ibmkanji[i].sjis;
701 c1 = (k >> 8) & 0xff;
702 c2 = k & 0xff;
703 }
704 }
705 }
706
707 if (k < 0xeb3f)
708 {
709 /* JIS X0208 */
710 *p++ = ((c1 & 0x3f) << 1) + 0x9f + (c2 > 0x9e);
711 *p++ = c2 + ((c2 > 0x9e) ? 2 : 0x60) + (c2 < 0x80);
712 }
713 else if ((k >= 0xeb40 && k < 0xf040) || (k >= 0xfc4c && k <= 0xfcfc))
714 {
715 /* NEC selection IBM kanji - Other undecided justice */
716 *p++ = PGEUCALTCODE >> 8;
717 *p++ = PGEUCALTCODE & 0xff;
718 }
719 else if (k >= 0xf040 && k < 0xf540)
720 {
721 /*
722 * UDC1 mapping to X0208 85 ku - 94 ku JIS code 0x7521 -
723 * 0x7e7e EUC 0xf5a1 - 0xfefe
724 */
725 c1 -= 0x6f;
726 *p++ = ((c1 & 0x3f) << 1) + 0xf3 + (c2 > 0x9e);
727 *p++ = c2 + ((c2 > 0x9e) ? 2 : 0x60) + (c2 < 0x80);
728 }
729 else if (k >= 0xf540 && k < 0xfa40)
730 {
731 /*
732 * UDC2 mapping to X0212 85 ku - 94 ku JIS code 0x7521 -
733 * 0x7e7e EUC 0x8ff5a1 - 0x8ffefe
734 */
735 *p++ = SS3;
736 c1 -= 0x74;
737 *p++ = ((c1 & 0x3f) << 1) + 0xf3 + (c2 > 0x9e);
738 *p++ = c2 + ((c2 > 0x9e) ? 2 : 0x60) + (c2 < 0x80);
739 }
740 else if (k >= 0xfa40)
741 {
742 /*
743 * mapping IBM kanji to X0208 and X0212
744 *
745 */
746 for (i = 0;; i++)
747 {
748 k2 = ibmkanji[i].sjis;
749 if (k2 == 0xffff)
750 break;
751 if (k2 == k)
752 {
753 k = ibmkanji[i].euc;
754 if (k >= 0x8f0000)
755 {
756 *p++ = SS3;
757 *p++ = 0x80 | ((k & 0xff00) >> 8);
758 *p++ = 0x80 | (k & 0xff);
759 }
760 else
761 {
762 *p++ = 0x80 | (k >> 8);
763 *p++ = 0x80 | (k & 0xff);
764 }
765 }
766 }
767 }
768 }
769 sjis += l;
770 len -= l;
771 }
772 *p = '\0';
773
774 return sjis - start;
775}
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1126
static int mic2euc_jp(const unsigned char *mic, unsigned char *p, int len, bool noError)
#define PGSJISALTCODE
Datum mic_to_sjis(PG_FUNCTION_ARGS)
Datum euc_jp_to_sjis(PG_FUNCTION_ARGS)
PG_MODULE_MAGIC_EXT(.name="euc_jp_and_sjis",.version=PG_VERSION)
static int sjis2euc_jp(const unsigned char *sjis, unsigned char *p, int len, bool noError)
PG_FUNCTION_INFO_V1(euc_jp_to_sjis)
Datum euc_jp_to_mic(PG_FUNCTION_ARGS)
static int sjis2mic(const unsigned char *sjis, unsigned char *p, int len, bool noError)
Datum sjis_to_euc_jp(PG_FUNCTION_ARGS)
Datum mic_to_euc_jp(PG_FUNCTION_ARGS)
Datum sjis_to_mic(PG_FUNCTION_ARGS)
static int euc_jp2mic(const unsigned char *euc, unsigned char *p, int len, bool noError)
static int euc_jp2sjis(const unsigned char *euc, unsigned char *p, int len, bool noError)
#define PGEUCALTCODE
static int mic2sjis(const unsigned char *mic, unsigned char *p, int len, bool noError)
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
return str start
int i
Definition: isn.c:77
void report_untranslatable_char(int src_encoding, int dest_encoding, const char *mbstr, int len)
Definition: mbutils.c:1730
void report_invalid_encoding(int encoding, const char *mbstr, int len)
Definition: mbutils.c:1698
const void size_t len
#define ISSJISTAIL(c)
Definition: pg_wchar.h:45
@ PG_MULE_INTERNAL
Definition: pg_wchar.h:233
@ PG_SJIS
Definition: pg_wchar.h:264
@ PG_EUC_JP
Definition: pg_wchar.h:227
#define SS2
Definition: pg_wchar.h:38
#define LC_JISX0208
Definition: pg_wchar.h:134
#define CHECK_ENCODING_CONVERSION_ARGS(srcencoding, destencoding)
Definition: pg_wchar.h:507
#define ISSJISHEAD(c)
Definition: pg_wchar.h:44
#define LC_JISX0212
Definition: pg_wchar.h:136
#define LC_JISX0201K
Definition: pg_wchar.h:113
#define SS3
Definition: pg_wchar.h:39
uintptr_t Datum
Definition: postgres.h:69
const char * name
int pg_encoding_verifymbchar(int encoding, const char *mbstr, int len)
Definition: wchar.c:2189