1 /*
2  * codeconv.c
3  * Copyright(c) 2001 Takashi NEMOTO
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * Written by Takashi Nemoto (tnemoto@mvi.biglobe.ne.jp).
16  * Modified by Kazuhiko <kazuhiko@ring.gr.jp>
17  * Modified by Satomi <satomi@ring.gr.jp>
18  *
19  */
20 
21 /* #define DEBUG_CODECONV */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "codeconv.h"
28 
29 #ifdef HAVE_SYS_TYPES_H
30 #  include <sys/types.h>
31 #endif
32 
33 #include <stdio.h>
34 
35 #ifdef HAVE_STDLIB_H
36 #  include <stdlib.h>
37 #endif
38 
39 #ifdef HAVE_LOCALE_H
40 #  include <locale.h>
41 #endif
42 
43 #ifdef HAVE_ICONV_H
44 #  include <iconv.h>
45 #endif
46 
47 #ifdef HAVE_ERRNO_H
48 #  include <errno.h>
49 #endif
50 
51 #ifdef HAVE_STRING_H
52 #  include <string.h>
53 #endif
54 
55 #ifdef HAVE_LANGINFO_H
56 #include <langinfo.h>
57 #endif
58 
59 #ifndef HAVE_MEMCPY
60 #define memcpy(d, s, n) bcopy((s), (d), (n))
61 #ifdef __STDC__
62 void *memchr(const void *, int, size_t);
63 int memcmp(const void *, const void *, size_t);
64 void *memmove(void *, const void *, size_t);
65 void *memset(void *, int, size_t);
66 #else /* not __STDC__ */
67 char *memchr();
68 int memcmp();
69 char *memmove();
70 char *memset();
71 #endif /* not __STDC__ */
72 #endif
73 
74 #ifdef HAVE_ICONV
75 static iconv_t cur_to_euc = (iconv_t)-1;
76 static iconv_t euc_to_cur = (iconv_t)-1;
77 static const char *eucjp_code_name = NULL;
78 #endif
79 
80 /* Return code <0: error, -2: Output Buffer Overflow */
81 size_t current_to_euc PROTO((char **current, size_t *in_len,
82 			     char **euc, size_t *out_len));
83 static size_t euc_to_current PROTO((char **euc, size_t *in_len,
84 				   char **current, size_t *out_len));
85 
86 
87 enum CONV_MODE {IO_AUTO, IO_ICONV, IO_SJIS, IO_EUC} conv_mode;
88 
89 static enum CONV_MODE detect_conv_mode PROTO((const char *encoding));
90 
91 
92 
93 
94 #define TMP_SIZE 10240
95 
96 static int	xputs_raw	PROTO((const char *str, int len, FILE *fp));
97 static int	xputs2		PROTO((const char *str, int len, FILE *fp));
98 
99 static const char *euc_jp_names[] = {
100     "eucJP", "EUC-JP", "eucjp", "euc-jp", "EUCJP", "ujis", "UJIS",
101     "euc", "EUC", NULL
102 };
103 
104 static const char *shift_jis_names[] = {
105     "SHIFT-JIS", "SHIFT_JIS", "SJIS", "CSSHIFTJIS", "SHIFTJIS", NULL
106 };
107 
108 #ifdef HAVE_ICONV
109 static const char *iso_2022_jp_names[] = {
110   "ISO-2022-JP-3", "ISO-2022-JP-2", "ISO-2022-JP",
111   "CSISO2022JP", "CSISO2022JP2", "CSISO2022JP3",
112   "ISO-2022", "ISO2022", "ISO2022JP", "ISO2022-JP", "JIS", NULL
113 };
114 
115 static const char *japanese_names[] = {
116     "ja", "japanese", NULL
117 };
118 #endif
119 
match_str(str,str_list)120 static int match_str(str,str_list)
121      const char *str;
122      const char **str_list;
123 {
124     const char **ptr;
125     for(ptr=str_list;*ptr!=NULL;ptr++) {
126       if (strcasecmp(str,*ptr)==0) return 1;
127     }
128     return 0;
129 }
130 
131 /*
132 
133  �������Ѵ��ؿ���������
134 
135 
136  1. encoding �����ꤵ��Ƥ����顢�ޤ����ꤵ�줿 encoding ��
137    1a. �ޤ� ���ꤵ�줿 encoding �� EUC/SJIS ���ɤ�����Ƚ�� => IO_EUC / IO_SJIS
138    1b. ����ʤ� iconv ���Ѵ��Ǥ��� encoding ����Ƚ��       => IO_ICONV
139    �ʲ�Ʊ�͡�
140 
141  2. ���˽�����Ѥߤ��ä��� �����ǽ�λ
142 
143  3. ����ʤ� locale ����μ������ߤ�
144    3a. nl_langinfo(CODESET) ����� encoding ���Ф����ߤ롣
145    3b. LC_CTYPE ����� encoding ���Ф����ߤ롣
146    2e. LC_CTYPE ��Ⱦ��(.�ʹ�) ����� encoding ���Ф����ߤ롣
147 
148  3. FALLBACK_ENCODING ��
149 
150  4. �������� EUC_JP
151 
152    ����ˤʤ���
153    SJIS �� locale ̾�� ja/japanese �ξ��
154           iconv ��ͭ���� => EUC_JP �� iconv ̾�ϡ�
155 	  iconv ��̵����� => 4. �� EUC_JP ���ʡ�
156    locale �� C �Ȥ� en_US ���ä��顩 => ���� FALLBACK ���롣
157         gettext �б����ξ����׼�ľ����
158 
159  */
160 
161 #ifdef HAVE_ICONV
162 
163 static int
setup_eucjp_code_name()164 setup_eucjp_code_name()
165 {
166     const char **enc;
167     iconv_t ic;
168     if (eucjp_code_name == NULL) {
169         for (enc = euc_jp_names; *enc != NULL; enc++) {
170 	    ic = iconv_open(*enc, *enc);
171 	    if (ic != (iconv_t)-1) {
172 	        eucjp_code_name = *enc;
173 		iconv_close(ic);
174 		break;
175 	    }
176 	}
177 	if (eucjp_code_name == NULL) {
178 	    /* EUC-JP ����˼��� - ۣ��� "ja" "japanese" �� */
179 	    for (enc = japanese_names; *enc != NULL; enc++) {
180 	        ic = iconv_open(*enc,*enc);
181 		if (ic != (iconv_t)-1) {
182 		    eucjp_code_name = *enc;
183 		    iconv_close(ic);
184 		    break;
185 		}
186 	    }
187 	}
188     }
189     return eucjp_code_name != NULL;
190 }
191 
192 /* Current locale �� codeset �����ܸ줬�����뤫��
193    ���Ԥʤ� 0, �����ʤ� 1 ���֤� */
194 
195 static int
iconv_test(ctoe,etoc)196 iconv_test(ctoe, etoc)
197      iconv_t ctoe, etoc;
198 {
199   /* ʸ���� "�¸�" */
200 #define TEST_STRING "\xBC\xC2\xB8\xB3"
201 #define TEST_LENGTH 50
202     char test1_0[TEST_LENGTH],test2_0[TEST_LENGTH],test3_0[TEST_LENGTH];
203     char *test1,*test2,*test3;
204     size_t ilen,olen;
205 
206     if (ctoe == (iconv_t)-1 || etoc == (iconv_t)-1)
207         return 0;
208     strcpy(test1_0,TEST_STRING);
209     test1=test1_0;
210     test2=test2_0;
211     test3=test3_0;
212     ilen=strlen(TEST_STRING);
213     olen=TEST_LENGTH;
214 
215     /* euc-jp => current code ���Ѵ��ƥ��� */
216     if (iconv(etoc,&test1,&ilen,&test2,&olen) == ((size_t)-1))
217         return 0;
218     if (iconv(etoc,NULL,&ilen,&test2,&olen) == ((size_t)-1))
219         return 0;
220 
221     /* current code ���� ������뤫 */
222     test2=test2_0;
223     ilen=TEST_LENGTH-olen;
224     olen=TEST_LENGTH;
225     if (iconv(ctoe,&test2,&ilen,&test3,&olen) == ((size_t)-1))
226         return 0;
227     if (iconv(ctoe,NULL,&ilen,&test3,&olen) == ((size_t)-1))
228         return 0;
229 
230     if (strncmp(test1_0,test3_0,strlen(test1_0)) != 0)
231         return 0;
232 
233     return 1;
234 }
235 
236 static int
iconv_setup(current_code_name)237 iconv_setup(current_code_name)
238      const char *current_code_name;
239 {
240     iconv_t ctoe,etoc;
241     static int disable_iconv = 0;
242 
243     if (disable_iconv)
244         return 0;
245     if (eucjp_code_name == NULL) {
246         if (! setup_eucjp_code_name()) {
247 	    disable_iconv = 1;
248 	    return 0;
249 	}
250     }
251 
252     if (current_code_name == NULL || eucjp_code_name == NULL)
253         return 0;
254 
255     ctoe = iconv_open(eucjp_code_name, current_code_name);
256     etoc = iconv_open(current_code_name, eucjp_code_name);
257 
258 
259     if (iconv_test(ctoe, etoc)) {
260         /* ���ޤ����ä��� ���ꤹ�� */
261         if (cur_to_euc != (iconv_t) -1)
262 	    iconv_close(cur_to_euc);
263 	if (euc_to_cur != (iconv_t) -1)
264 	    iconv_close(euc_to_cur);
265 	cur_to_euc=ctoe;
266 	euc_to_cur=etoc;
267 	return 1;
268     } else {
269         if (ctoe != (iconv_t)-1)
270 	    iconv_close(ctoe);
271 	if (etoc != (iconv_t)-1)
272 	    iconv_close(etoc);
273 	return 0;
274     }
275 }
276 #endif
277 
detect_conv_mode(encoding)278 enum CONV_MODE detect_conv_mode(encoding)
279      const char *encoding;
280 {
281     if (encoding == NULL) return IO_AUTO;
282     if (match_str(encoding,euc_jp_names)) return IO_EUC;
283     if (match_str(encoding,shift_jis_names)) return IO_SJIS;
284 #ifdef HAVE_ICONV
285     if (match_str(encoding,iso_2022_jp_names)) {
286         const char **enc;
287 	for(enc = iso_2022_jp_names;*enc != NULL; enc++){
288 	    if (iconv_setup(*enc))
289 	        return IO_ICONV;
290 	}
291     } else if (iconv_setup(encoding)) {
292         return IO_ICONV;
293     }
294 #endif
295     return IO_AUTO;
296 }
297 
298 int
locale_init(encoding)299 locale_init(encoding)
300      const char *encoding;
301 {
302     static int		initialized = 0;
303 #ifdef HAVE_SETLOCALE
304     static char *locale_name = NULL;
305     static char *current_code_name = NULL;
306 #endif
307     enum CONV_MODE cm_temp;
308 
309 #ifdef HAVE_SETLOCALE
310     locale_name = setlocale(LC_CTYPE, "");
311 #endif
312 
313     /* 1. encoding �ˤ�����
314             �� ͭ���� encoding �����ꤵ���а������ͤ���  */
315     cm_temp = detect_conv_mode(encoding);
316     if (cm_temp != IO_AUTO) {
317         conv_mode = cm_temp;
318         goto init_finish;
319     }
320 
321     /* ���Ǥ� ������ѤߤǤ���� ���Τޤ޵��� */
322     if (initialized != 0 &&
323 	(conv_mode != IO_ICONV
324 #ifdef HAVE_ICONV
325 	 || (cur_to_euc != (iconv_t)-1 && euc_to_cur != (iconv_t)-1)
326 #endif
327 	 ))
328 	return CODECONV_OK;
329     initialized = 0;
330     conv_mode = IO_AUTO;
331 
332 #ifdef HAVE_SETLOCALE
333     /* 2. current_locale ���� ������ߤ� */
334 #if defined(HAVE_NL_LANGINFO) && defined(CODESET)
335     /* 2a/2b. nl_langinfo(CODESET) ����μ����λ�� */
336     current_code_name=nl_langinfo(CODESET);
337     conv_mode=detect_conv_mode(current_code_name);
338     if (conv_mode != IO_AUTO)
339         goto init_finish;
340 #endif
341     /* 2c/2d. locale LC_CTYPE ���Τ�Τγ�ǧ */
342     conv_mode=detect_conv_mode(locale_name);
343     if (conv_mode != IO_AUTO)
344         goto init_finish;
345 
346     /* 2e/2f. locale LC_CTYPE ��Ⱦ���γ�ǧ */
347     if (locale_name != NULL) {
348         char *try2;
349         locale_name = strdup(locale_name);
350 	if (locale_name == NULL)
351 	    return CODECONV_ERROR;
352 	try2 = strtok(locale_name, ".@");
353 	if (try2 != NULL)
354 	    try2 = strtok(NULL, ".@");
355 	if (try2 != NULL) {
356 	    conv_mode = detect_conv_mode(try2);
357 	    if (conv_mode != IO_AUTO) goto init_finish;
358 	}
359     }
360 #endif /* HAVE_SETLOCALE */
361 
362     /* 3a/3b. ����Ǥ����ʤ� FALLBACK ���� */
363 #ifdef FALLBACK_ENCODING
364     conv_mode = detect_conv_mode(FALLBACK_ENCODING);
365 #endif
366 
367     /* 4. �������� EUC_JP */
368     if (conv_mode == IO_AUTO) conv_mode = IO_EUC;
369 
370  init_finish:
371     initialized = 1;
372     return CODECONV_OK;
373 }
374 
375 static int
xputs_raw(str,len,fp)376 xputs_raw(str, len, fp)
377      const char	*str;
378      int	len;
379      FILE	*fp;
380 {
381     int outlen = 0;
382     int len1 = len;
383     int wlen;
384 
385     while (outlen < len) {
386         wlen = fwrite(str, 1, len1, fp);
387 	if (wlen == 0)
388 	    break;
389 	outlen += wlen;
390 	len1 -= wlen;
391 	str += wlen;
392     }
393     return outlen;
394 }
395 
396 /* Convert ISO8859-1 NO-BREAK SPACE to normal SPACE */
397 /* NBSP(0xa0) �� EUC-JP �Ȥ֤Ĥ���ʤ�Ȧ */
398 static int
convert_nbsp(str,len)399 convert_nbsp(str, len)
400      char *str;
401      int len;
402 {
403     while(len>0) {
404       if (((*str) & 0xff) == 0xa0) *str = 0x20;
405       str++;
406       len--;
407     }
408     return 1;
409 }
410 
411 static int
xputs2(str,len,fp)412 xputs2(str, len, fp)
413      const char	*str;
414      int	len;
415      FILE	*fp;
416 {
417     char	*buf1p, *buf1p0;
418     char	*buf2p, *buf2p0;
419     size_t	len1, len2;
420     size_t	outlen;
421     int		ret_code;
422     size_t	status;
423 
424     /* The maximum size of output is 4 times larger than input. */
425     outlen = len * 4;
426 
427     len1 = len;
428     len2 = outlen;
429 #ifdef HAVE_ALLOCA
430     buf1p = buf1p0 = alloca(len1);
431 #else
432     buf1p = buf1p0 = malloc(len1);
433 #endif
434     if (buf1p == NULL)
435 	return EOF;
436 #ifdef HAVE_ALLOCA
437     buf2p = buf2p0 = alloca(len2);
438 #else
439     buf2p = buf2p0 = malloc(len2);
440 #endif
441     if (buf2p == NULL) {
442         free(buf1p0);
443 	return EOF;
444     }
445     memcpy(buf1p, str, len);
446     convert_nbsp(buf1p, len);
447     status=euc_to_current(&buf1p, &len1, &buf2p, &len2);
448     if (status == -2) { /* ������ �����ΰ����� */
449         buf1p = buf1p0;
450 	len1 = len;
451         outlen *= 3;
452 	len2 = outlen;
453 #ifdef HAVE_ALLOCA
454         buf2p = buf2p0 = alloca(outlen);
455 #else
456 	free(buf2p0);
457 	buf2p = buf2p0 = malloc(outlen);
458 #endif
459 	if (buf2p == NULL){
460 	    free(buf1p0);
461 	    return EOF;
462 	}
463 	status=euc_to_current(&buf1p, &len1, &buf2p, &len2);
464     }
465     if (status == CODECONV_ERROR || status == CODECONV_BUFFER_OVERFLOW) {
466         /* Conversion Error  �������� ���Τޤ޽��� */
467 #ifndef HAVE_ALLOCA
468         free(buf1p0);
469         free(buf2p0);
470 #endif
471         return xputs_raw(str, len, fp);
472     }
473 #ifndef HAVE_ALLOCA
474     free(buf1p0);
475 #endif
476     ret_code = xputs_raw(buf2p0, outlen - len2, fp);
477 #ifndef HAVE_ALLOCA
478     free(buf2p0);
479 #endif
480     return ret_code;
481 }
482 
483 int
xfputs(str,fp)484 xfputs(str, fp)
485      const char *str;
486      FILE* fp;
487 {
488     return xputs2(str, strlen(str), fp);
489 }
490 
491 int
xputs(str)492 xputs(str)
493      const char *str;
494 {
495     int len;
496     len=xfputs(str, stdout);
497     if (len<0) return EOF;
498     putchar('\n');
499     return len+1;
500 }
501 
502 int
xvfprintf(fp,fmt,ap)503 xvfprintf(fp, fmt, ap)
504     FILE *fp;
505     const char *fmt;
506     va_list ap;
507 {
508     char buf1[TMP_SIZE];
509     int len;
510 #ifdef HAVE_VSNPRINTF
511     len = vsnprintf(buf1, TMP_SIZE - 1, fmt, ap);
512     buf1[TMP_SIZE - 1]=0;
513 #else
514     len = vsprintf(buf1, fmt, ap);
515 #endif
516     return xputs2(buf1, len, fp);
517 }
518 
519 /* USE_STDARG_H is defined in codeconv.h */
520 #ifdef USE_STDARG_H
521 int
xfprintf(FILE * fp,const char * fmt,...)522 xfprintf(FILE *fp, const char *fmt, ...)
523 #else
524 int
525 xfprintf(fp, fmt, va_alist)
526     FILE	*fp;
527     const char	*fmt;
528     va_dcl
529 #endif
530 {
531     int len;
532     va_list ap;
533 #ifdef USE_STDARG_H
534     va_start(ap, fmt);
535 #else
536     va_start(ap);
537 #endif
538     len = xvfprintf(fp, fmt, ap);
539     va_end(ap);
540     return len;
541 }
542 
543 int
544 #ifdef USE_STDARG_H
xprintf(const char * fmt,...)545 xprintf(const char *fmt, ...)
546 #else
547 xprintf(fmt, va_alist)
548     const char *fmt;
549     va_dcl
550 #endif
551 {
552     int len;
553     va_list ap;
554 #ifdef USE_STDARG_H
555     va_start(ap, fmt);
556 #else
557     va_start(ap);
558 #endif
559     len = xvfprintf(stdout, fmt, ap);
560     va_end(ap);
561     return len;
562 }
563 
564 char *
xfgets(str,size,fp)565 xfgets(str, size, fp)
566      char *str;
567      int size;
568      FILE *fp;
569 {
570     char *ibuf, *ibuf0;
571     size_t ilen;
572     size_t status;
573     char *str0;
574     int size0;
575 
576     str0 = str;
577     size0 = size;
578 
579     /* The maximum size of input is 4 times larger than size. */
580     ilen = size * 4;
581 #ifdef HAVE_ALLOCA
582     ibuf0 = ibuf = alloca(ilen+1);
583 #else
584     ibuf0 = ibuf = malloc(ilen+1);
585 #endif
586     if (ibuf == NULL)
587         return NULL;
588 
589     if (fgets(ibuf, ilen, fp) == NULL) {
590 #ifndef HAVE_ALLOCA
591         free(ibuf);
592 #endif
593         return NULL;
594     }
595     ibuf[ilen]=0;
596     ilen=strlen(ibuf);
597 
598     status = current_to_euc(&ibuf,&ilen,&str,(size_t *)&size);
599     str0[size0-size]=0;
600 #ifndef HAVE_ALLOCA
601     free(ibuf0);
602 #endif
603     if (status != CODECONV_ERROR) return str0;
604     return NULL;
605 }
606 
607 /* ================================================================== */
608 
609 char*
jis_to_euc(euc,jis,len)610 jis_to_euc(euc, jis, len)
611      char	*euc;
612      const char *jis;
613      int	len;
614 {
615     const char	*jis_end;
616     char	*q;
617     jis_end = jis + len;
618     /* Remove white space at tail of string */
619     while (jis_end >= jis + 2 &&
620 	((jis_end[-1] == '\0' && jis_end[-2] == '\0') ||
621 	 (jis_end[-1] == 0x21 && jis_end[-2] == 0x21)))
622 	jis_end -= 2;
623     q = euc;
624     while (jis < jis_end)
625 	*q++ = (*jis++ | 0x80);
626     *q = '\0';
627     return (char *)euc;
628 }
629 
630 char*
euc_to_jis(jis,euc,len)631 euc_to_jis(jis, euc, len)
632      char	*jis;
633      const char *euc;
634      int	len;
635 {
636     const char	*euc_end;
637     char 	*q;
638     euc_end = euc + len;
639     /* Remove white space at tail of string */
640     while (euc_end >= euc + 2 &&
641 	((euc_end[-1] == '\0' && euc_end[-2] == '\0') ||
642 	 (euc_end[-1] == 0x21 && euc_end[-2] == 0x21)))
643 	euc_end -= 2;
644     q = jis;
645     while (euc < euc_end)
646 	*q++ = (*euc++ & 0x7f);
647     *q = '\0';
648     return (char *)jis;
649 }
650 
current_to_euc(in_buf,in_len,out_buf,out_len)651 size_t current_to_euc (in_buf,in_len,out_buf,out_len)
652      char **in_buf, **out_buf;
653      size_t *in_len,*out_len;
654 {
655     static int output_left = -1;
656     int c1, c2;
657     size_t count = 0;
658 
659 #ifdef HAVE_ICONV
660     if (conv_mode == IO_ICONV) {
661         size_t ret;
662         if (cur_to_euc == (iconv_t) -1)
663 	    return CODECONV_ERROR;
664         ret = iconv(cur_to_euc,in_buf,in_len,out_buf,out_len);
665 	if (ret != ((size_t)-1))
666 	    ret = iconv(cur_to_euc, NULL, in_len, out_buf, out_len);
667 #if defined (HAVE_ERRNO_H) && defined (E2BIG)
668 	if (ret == ((size_t)-1)) {
669 	    if (errno == E2BIG)
670 	        return CODECONV_BUFFER_OVERFLOW;
671 	    return CODECONV_ERROR;
672 	}
673 #endif /* HAVE_ERRNO_H / E2BIG */
674 	return ret;
675     }
676 #endif /* HAVE_ICONV */
677 
678     if (output_left >= 0) {
679         if (*out_len > 0) {
680 	    *((*in_buf)++) = output_left;
681 	    (*out_len)--;
682 	    count++;
683 	    output_left = -1;
684 	} else {
685   	    /* Output Buffer Overflow */
686 	    return CODECONV_BUFFER_OVERFLOW;
687 	}
688     }
689     if (conv_mode == IO_SJIS) {
690         while(*in_len>0) {
691 	    if (*out_len<=0) break;
692 	    c1 = *((*in_buf)++) & 0xff;
693 	    (*in_len)--;
694 	    if (c1 < 0x80) { /* ASCII ʸ�� */
695 	        (*out_len)--;
696 		count++;
697 		*((*out_buf)++)=c1;
698 		continue;
699 	    } else if ((c1 < 0x81 || c1 > 0x9f) && (c1 < 0xe0 || c1 > 0xef)) {
700 		/*  Ⱦ�ѥ��� */
701 		if (0xa1 <= c1 && c1 <= 0xdf) {
702 		    c2 = c1 - 0x80;
703 		    c1 = 0x8e;
704 		} else {
705 		    return -1;
706 		}
707 	    } else {
708 		c2 = *((*in_buf)++) & 0xff;
709 		(*in_len)--;
710 		if (c1 > 0x9f)
711 		    c1 -= 0x40;
712 		c1 += c1;
713 		if (c2 <= 0x9e) {
714 		    c1 -= 0xe1;
715 		    if (c2 >= 0x80)
716 			c2 -= 1;
717 		    c2 -= 0x1f;
718 		} else {
719 		    c1 -= 0xe0;
720 		    c2 -= 0x7e;
721 		}
722 		c2 |= 0x80;
723 	    }
724 	    *((*out_buf)++) = c1 | 0x80;
725 	    (*out_len)--;
726 	    count++;
727 	    if (*out_len <= 0) {
728 	        output_left = c2;
729 		return CODECONV_BUFFER_OVERFLOW;
730 	    }
731 	    *((*out_buf)++) = c2;
732 	    (*out_len)--;
733 	    count++;
734 	}
735 	if (*in_len == 0) return count;
736 	if (*out_len == 0) return CODECONV_BUFFER_OVERFLOW;
737 	return CODECONV_ERROR;
738     } else { /* IO_EUC */
739         if (*out_len < *in_len) {
740 	    memcpy(*out_buf,*in_buf,*out_len);
741 	    count = *out_len;
742 	    (*out_buf) += *out_len;
743 	    (*in_buf) += *out_len;
744 	    (*in_len) -= *out_len;
745 	    *out_len = 0;
746 	    return CODECONV_BUFFER_OVERFLOW;
747 	} else {
748 	    memcpy(*out_buf,*in_buf,*in_len);
749 	    count = *in_len;
750 	    (*out_buf)+=*in_len;
751 	    (*in_buf)+=*in_len;
752 	    (*out_len)-=*in_len;
753 	    *in_len=0;
754 	    return count;
755 	}
756     }
757     return CODECONV_ERROR; /* Never */
758 }
759 
euc_to_current(in_buf,in_len,out_buf,out_len)760 size_t euc_to_current (in_buf,in_len,out_buf,out_len)
761      char **in_buf, **out_buf;
762      size_t *in_len,*out_len;
763 {
764     static int output_left = -1;
765     int c1, c2;
766     size_t count = 0;
767 
768 #ifdef HAVE_ICONV
769     if (conv_mode == IO_ICONV) {
770         size_t ret;
771         if (euc_to_cur == (iconv_t) -1)
772 	    return CODECONV_ERROR;
773         ret = iconv(euc_to_cur,in_buf,in_len,out_buf,out_len);
774         if (ret != ((size_t)-1))
775 	    ret = iconv(euc_to_cur,NULL,in_len,out_buf,out_len);
776 #if defined (HAVE_ERRNO_H) && defined (E2BIG)
777 	if (ret == ((size_t)-1)) {
778 	    if (errno == E2BIG)
779 	        return CODECONV_BUFFER_OVERFLOW;
780 	    return CODECONV_ERROR;
781 	}
782 #endif /* HAVE_ERRNO_H / E2BIG */
783 	return ret;
784     }
785 #endif /* HAVE_ICONV */
786 
787     if (output_left >= 0) {
788         if (*out_len > 0) {
789 	    *((*in_buf)++) = output_left;
790 	    (*out_len)--;
791 	    count++;
792 	    output_left = -1;
793 	} else {
794   	    /* Output Buffer Overflow */
795 	    return CODECONV_BUFFER_OVERFLOW;
796 	}
797     }
798     if (conv_mode == IO_SJIS) {
799         while(*in_len>0) {
800 	    if (*out_len<=0) break;
801 	    c1 = *((*in_buf)++) & 0xff;
802 	    (*in_len)--;
803 	    if ((c1 & 0x80) == 0) {
804 	        *((*out_buf)++) = c1;
805 		(*out_len)--;
806 		count++;
807 		continue;
808 	    }
809 	    if (0x8e == c1) {
810 	        *((*out_buf)++) = *((*in_buf)++) | 0x80;
811 	        (*in_len)--;
812 	        (*out_len)--;
813 	        count++;
814 	        continue;
815 	    }
816 	    c1 &= 0x7f;
817 	    c2 = *((*in_buf)++) & 0x7f;
818 	    (*in_len)--;
819 	    if (c1 & 0x01) {
820 	        c2 += 0x1f;
821 		if (c2 > 0x7e)
822 		    c2++;
823 	    } else {
824 	        c2 += 0x7e;
825 	    }
826 	    c1 = (c1 + 0xe1) >> 1;
827 	    if (c1 > 0x9f)
828 	        c1 += 0x40;
829 	    *((*out_buf)++) = c1;
830 	    (*out_len)--;
831 	    count++;
832 	    if (*out_len <= 0) {
833 	        output_left = c2;
834 		return CODECONV_BUFFER_OVERFLOW;
835 	    }
836 	    *((*out_buf)++) = c2;
837 	    (*out_len)--;
838 	    count++;
839 	}
840 	if (*in_len == 0) return count;
841 	if (*out_len == 0) return CODECONV_BUFFER_OVERFLOW;
842 	return CODECONV_ERROR;
843     } else { /* IO_EUC */
844         if (*out_len < *in_len) {
845 	    memcpy(*out_buf,*in_buf,*out_len);
846 	    count  = *out_len;
847 	    (*out_buf)+=*out_len;
848 	    (*in_buf)+=*out_len;
849 	    (*in_len)-=*out_len;
850 	    *out_len=0;
851 	    return CODECONV_BUFFER_OVERFLOW;
852 	} else {
853 	    memcpy(*out_buf,*in_buf,*in_len);
854 	    count  = *in_len;
855 	    (*out_buf)+=*in_len;
856 	    (*in_buf)+=*in_len;
857 	    (*out_len)-=*in_len;
858 	    *in_len=0;
859 	    return count;
860 	}
861     }
862     return CODECONV_ERROR; /* Never */
863 }
864 
865