xref: /freebsd-src/contrib/nvi/common/conv.c (revision 110d525ec6188f3c9dc4f54c4bc1cced2f7184cd)
1f0957ccaSPeter Wemm /*-
2f0957ccaSPeter Wemm  * Copyright (c) 1993, 1994
3f0957ccaSPeter Wemm  *	The Regents of the University of California.  All rights reserved.
4f0957ccaSPeter Wemm  * Copyright (c) 1993, 1994, 1995, 1996
5f0957ccaSPeter Wemm  *	Keith Bostic.  All rights reserved.
6f0957ccaSPeter Wemm  * Copyright (c) 2011, 2012
7f0957ccaSPeter Wemm  *	Zhihao Yuan.  All rights reserved.
8f0957ccaSPeter Wemm  *
9f0957ccaSPeter Wemm  * See the LICENSE file for redistribution information.
10f0957ccaSPeter Wemm  */
11f0957ccaSPeter Wemm 
12f0957ccaSPeter Wemm #include "config.h"
13f0957ccaSPeter Wemm 
14f0957ccaSPeter Wemm #include <sys/types.h>
15f0957ccaSPeter Wemm #include <sys/queue.h>
16f0957ccaSPeter Wemm #include <sys/time.h>
17f0957ccaSPeter Wemm 
18f0957ccaSPeter Wemm #include <bitstring.h>
19f0957ccaSPeter Wemm #include <errno.h>
20f0957ccaSPeter Wemm #include <limits.h>
21f0957ccaSPeter Wemm #include <langinfo.h>
22f0957ccaSPeter Wemm #include <locale.h>
23f0957ccaSPeter Wemm #include <stdio.h>
24f0957ccaSPeter Wemm #include <stdlib.h>
25f0957ccaSPeter Wemm #include <string.h>
26f0957ccaSPeter Wemm #include <strings.h>
27f0957ccaSPeter Wemm #include <unistd.h>
28f0957ccaSPeter Wemm 
29f0957ccaSPeter Wemm #include "common.h"
30f0957ccaSPeter Wemm 
31f0957ccaSPeter Wemm /*
32f0957ccaSPeter Wemm  * codeset --
33f0957ccaSPeter Wemm  *	Get the locale encoding.
34f0957ccaSPeter Wemm  *
35c271fa92SBaptiste Daroussin  * PUBLIC: char * codeset(void);
36f0957ccaSPeter Wemm  */
37f0957ccaSPeter Wemm char *
codeset(void)38c271fa92SBaptiste Daroussin codeset(void)
39c271fa92SBaptiste Daroussin {
40f0957ccaSPeter Wemm 	static char *cs;
41f0957ccaSPeter Wemm 
42f0957ccaSPeter Wemm 	if (cs == NULL)
43f0957ccaSPeter Wemm 		cs = nl_langinfo(CODESET);
44c271fa92SBaptiste Daroussin 
45f0957ccaSPeter Wemm 	return cs;
46f0957ccaSPeter Wemm }
47f0957ccaSPeter Wemm 
48f0957ccaSPeter Wemm #ifdef USE_WIDECHAR
49f0957ccaSPeter Wemm static int
raw2int(SCR * sp,const char * str,ssize_t len,CONVWIN * cw,size_t * tolen,CHAR_T ** dst)50c271fa92SBaptiste Daroussin raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
51c271fa92SBaptiste Daroussin     CHAR_T **dst)
52f0957ccaSPeter Wemm {
53f0957ccaSPeter Wemm 	int i;
54f0957ccaSPeter Wemm 	CHAR_T **tostr = &cw->bp1.wc;
55f0957ccaSPeter Wemm 	size_t  *blen = &cw->blen1;
56f0957ccaSPeter Wemm 
57f0957ccaSPeter Wemm 	BINC_RETW(NULL, *tostr, *blen, len);
58f0957ccaSPeter Wemm 
59f0957ccaSPeter Wemm 	*tolen = len;
60f0957ccaSPeter Wemm 	for (i = 0; i < len; ++i)
61f0957ccaSPeter Wemm 		(*tostr)[i] = (u_char) str[i];
62f0957ccaSPeter Wemm 
63f0957ccaSPeter Wemm 	*dst = cw->bp1.wc;
64f0957ccaSPeter Wemm 
65f0957ccaSPeter Wemm 	return 0;
66f0957ccaSPeter Wemm }
67f0957ccaSPeter Wemm 
68f0957ccaSPeter Wemm #define CONV_BUFFER_SIZE    512
69f0957ccaSPeter Wemm /* fill the buffer with codeset encoding of string pointed to by str
70f0957ccaSPeter Wemm  * left has the number of bytes left in str and is adjusted
71f0957ccaSPeter Wemm  * len contains the number of bytes put in the buffer
72f0957ccaSPeter Wemm  */
73f0957ccaSPeter Wemm #ifdef USE_ICONV
74f0957ccaSPeter Wemm #define CONVERT(str, left, src, len)					\
75f0957ccaSPeter Wemm 	do {								\
76f0957ccaSPeter Wemm 		size_t outleft;						\
77f0957ccaSPeter Wemm 		char *bp = buffer;					\
78f0957ccaSPeter Wemm 		outleft = CONV_BUFFER_SIZE;				\
79f0957ccaSPeter Wemm 		errno = 0;						\
80c271fa92SBaptiste Daroussin 		if (iconv(id, (iconv_src_t)&str, &left, &bp, &outleft)	\
81c271fa92SBaptiste Daroussin 		    == -1 && errno != E2BIG)				\
82f0957ccaSPeter Wemm 			goto err;					\
83f0957ccaSPeter Wemm 		if ((len = CONV_BUFFER_SIZE - outleft) == 0) {		\
84f0957ccaSPeter Wemm 			error = -left;					\
85f0957ccaSPeter Wemm 			goto err;					\
86f0957ccaSPeter Wemm 		}							\
87f0957ccaSPeter Wemm 		src = buffer;						\
88f0957ccaSPeter Wemm 	} while (0)
89f0957ccaSPeter Wemm 
90f0957ccaSPeter Wemm #define IC_RESET()							\
91f0957ccaSPeter Wemm 	do {								\
92f0957ccaSPeter Wemm 		if (id != (iconv_t)-1)					\
93f0957ccaSPeter Wemm 			iconv(id, NULL, NULL, NULL, NULL);		\
94f0957ccaSPeter Wemm 	} while(0)
95f0957ccaSPeter Wemm #else
96f0957ccaSPeter Wemm #define CONVERT(str, left, src, len)
97f0957ccaSPeter Wemm #define IC_RESET()
98f0957ccaSPeter Wemm #endif
99f0957ccaSPeter Wemm 
100f0957ccaSPeter Wemm static int
default_char2int(SCR * sp,const char * str,ssize_t len,CONVWIN * cw,size_t * tolen,CHAR_T ** dst,iconv_t id)101f0957ccaSPeter Wemm default_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
102f0957ccaSPeter Wemm     size_t *tolen, CHAR_T **dst, iconv_t id)
103f0957ccaSPeter Wemm {
104f0957ccaSPeter Wemm 	size_t i = 0, j;
105f0957ccaSPeter Wemm 	CHAR_T **tostr = &cw->bp1.wc;
106f0957ccaSPeter Wemm 	size_t *blen = &cw->blen1;
107f0957ccaSPeter Wemm 	mbstate_t mbs;
108f0957ccaSPeter Wemm 	size_t n;
109f0957ccaSPeter Wemm 	ssize_t nlen = len;
110f0957ccaSPeter Wemm 	char *src = (char *)str;
111f0957ccaSPeter Wemm #ifdef USE_ICONV
112f0957ccaSPeter Wemm 	char buffer[CONV_BUFFER_SIZE];
113f0957ccaSPeter Wemm #endif
114f0957ccaSPeter Wemm 	size_t left = len;
115f0957ccaSPeter Wemm 	int error = 1;
116f0957ccaSPeter Wemm 
117*110d525eSBaptiste Daroussin 	memset(&mbs, 0, sizeof(mbs));
118f0957ccaSPeter Wemm 	BINC_RETW(NULL, *tostr, *blen, nlen);
119f0957ccaSPeter Wemm 
120f0957ccaSPeter Wemm #ifdef USE_ICONV
121f0957ccaSPeter Wemm 	if (id != (iconv_t)-1)
122f0957ccaSPeter Wemm 		CONVERT(str, left, src, len);
123f0957ccaSPeter Wemm #endif
124f0957ccaSPeter Wemm 
125f0957ccaSPeter Wemm 	for (i = 0, j = 0; j < len; ) {
126f0957ccaSPeter Wemm 		n = mbrtowc((*tostr)+i, src+j, len-j, &mbs);
127f0957ccaSPeter Wemm 		/* NULL character converted */
128c271fa92SBaptiste Daroussin 		if (n == -2)
129c271fa92SBaptiste Daroussin 			error = -(len-j);
130c271fa92SBaptiste Daroussin 		if (n == -1 || n == -2)
131c271fa92SBaptiste Daroussin 			goto err;
132c271fa92SBaptiste Daroussin 		if (n == 0)
133c271fa92SBaptiste Daroussin 			n = 1;
134f0957ccaSPeter Wemm 		j += n;
135f0957ccaSPeter Wemm 		if (++i >= *blen) {
136f0957ccaSPeter Wemm 			nlen += 256;
137f0957ccaSPeter Wemm 			BINC_RETW(NULL, *tostr, *blen, nlen);
138f0957ccaSPeter Wemm 		}
139f0957ccaSPeter Wemm 		if (id != (iconv_t)-1 && j == len && left) {
140f0957ccaSPeter Wemm 			CONVERT(str, left, src, len);
141f0957ccaSPeter Wemm 			j = 0;
142f0957ccaSPeter Wemm 		}
143f0957ccaSPeter Wemm 	}
144f0957ccaSPeter Wemm 
145f0957ccaSPeter Wemm 	error = 0;
146f0957ccaSPeter Wemm err:
147f0957ccaSPeter Wemm 	*tolen = i;
148f0957ccaSPeter Wemm 	*dst = cw->bp1.wc;
149f0957ccaSPeter Wemm 	IC_RESET();
150f0957ccaSPeter Wemm 
151f0957ccaSPeter Wemm 	return error;
152f0957ccaSPeter Wemm }
153f0957ccaSPeter Wemm 
154f0957ccaSPeter Wemm static int
fe_char2int(SCR * sp,const char * str,ssize_t len,CONVWIN * cw,size_t * tolen,CHAR_T ** dst)155c271fa92SBaptiste Daroussin fe_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
156c271fa92SBaptiste Daroussin     CHAR_T **dst)
157f0957ccaSPeter Wemm {
158f0957ccaSPeter Wemm 	return default_char2int(sp, str, len, cw, tolen, dst,
159f0957ccaSPeter Wemm 	    sp->conv.id[IC_FE_CHAR2INT]);
160f0957ccaSPeter Wemm }
161f0957ccaSPeter Wemm 
162f0957ccaSPeter Wemm static int
ie_char2int(SCR * sp,const char * str,ssize_t len,CONVWIN * cw,size_t * tolen,CHAR_T ** dst)163c271fa92SBaptiste Daroussin ie_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
164c271fa92SBaptiste Daroussin     CHAR_T **dst)
165f0957ccaSPeter Wemm {
166f0957ccaSPeter Wemm 	return default_char2int(sp, str, len, cw, tolen, dst,
167f0957ccaSPeter Wemm 	    sp->conv.id[IC_IE_CHAR2INT]);
168f0957ccaSPeter Wemm }
169f0957ccaSPeter Wemm 
170f0957ccaSPeter Wemm static int
cs_char2int(SCR * sp,const char * str,ssize_t len,CONVWIN * cw,size_t * tolen,CHAR_T ** dst)171c271fa92SBaptiste Daroussin cs_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
172c271fa92SBaptiste Daroussin     CHAR_T **dst)
173f0957ccaSPeter Wemm {
174c271fa92SBaptiste Daroussin 	return default_char2int(sp, str, len, cw, tolen, dst, (iconv_t)-1);
175f0957ccaSPeter Wemm }
176f0957ccaSPeter Wemm 
177f0957ccaSPeter Wemm static int
int2raw(SCR * sp,const CHAR_T * str,ssize_t len,CONVWIN * cw,size_t * tolen,char ** dst)178c271fa92SBaptiste Daroussin int2raw(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, size_t *tolen,
179c271fa92SBaptiste Daroussin     char **dst)
180f0957ccaSPeter Wemm {
181f0957ccaSPeter Wemm 	int i;
182f0957ccaSPeter Wemm 	char **tostr = &cw->bp1.c;
183f0957ccaSPeter Wemm 	size_t  *blen = &cw->blen1;
184f0957ccaSPeter Wemm 
185f0957ccaSPeter Wemm 	BINC_RETC(NULL, *tostr, *blen, len);
186f0957ccaSPeter Wemm 
187f0957ccaSPeter Wemm 	*tolen = len;
188f0957ccaSPeter Wemm 	for (i = 0; i < len; ++i)
189f0957ccaSPeter Wemm 		(*tostr)[i] = str[i];
190f0957ccaSPeter Wemm 
191f0957ccaSPeter Wemm 	*dst = cw->bp1.c;
192f0957ccaSPeter Wemm 
193f0957ccaSPeter Wemm 	return 0;
194f0957ccaSPeter Wemm }
195f0957ccaSPeter Wemm 
196f0957ccaSPeter Wemm static int
default_int2char(SCR * sp,const CHAR_T * str,ssize_t len,CONVWIN * cw,size_t * tolen,char ** pdst,iconv_t id)197f0957ccaSPeter Wemm default_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
198f0957ccaSPeter Wemm     size_t *tolen, char **pdst, iconv_t id)
199f0957ccaSPeter Wemm {
200f0957ccaSPeter Wemm 	size_t i, j, offset = 0;
201f0957ccaSPeter Wemm 	char **tostr = &cw->bp1.c;
202f0957ccaSPeter Wemm 	size_t *blen = &cw->blen1;
203f0957ccaSPeter Wemm 	mbstate_t mbs;
204f0957ccaSPeter Wemm 	size_t n;
205f0957ccaSPeter Wemm 	ssize_t  nlen = len + MB_CUR_MAX;
206f0957ccaSPeter Wemm 	char *dst;
207f0957ccaSPeter Wemm 	size_t buflen;
208f0957ccaSPeter Wemm #ifdef USE_ICONV
209f0957ccaSPeter Wemm 	char buffer[CONV_BUFFER_SIZE];
210f0957ccaSPeter Wemm #endif
211f0957ccaSPeter Wemm 	int error = 1;
212f0957ccaSPeter Wemm 
213f0957ccaSPeter Wemm /* convert first len bytes of buffer and append it to cw->bp
214f0957ccaSPeter Wemm  * len is adjusted => 0
215f0957ccaSPeter Wemm  * offset contains the offset in cw->bp and is adjusted
216f0957ccaSPeter Wemm  * cw->bp is grown as required
217f0957ccaSPeter Wemm  */
218f0957ccaSPeter Wemm #ifdef USE_ICONV
219f0957ccaSPeter Wemm #define CONVERT2(_buffer, lenp, cw, offset)				\
220f0957ccaSPeter Wemm 	do {								\
221f0957ccaSPeter Wemm 		char *bp = _buffer;					\
222f0957ccaSPeter Wemm 		int ret;						\
223f0957ccaSPeter Wemm 		do {							\
224f0957ccaSPeter Wemm 			size_t outleft = cw->blen1 - offset;		\
225f0957ccaSPeter Wemm 			char *obp = cw->bp1.c + offset;			\
226f0957ccaSPeter Wemm 			if (cw->blen1 < offset + MB_CUR_MAX) {		\
227f0957ccaSPeter Wemm 				nlen += 256;				\
228c271fa92SBaptiste Daroussin 				BINC_RETC(NULL, cw->bp1.c, cw->blen1,	\
229c271fa92SBaptiste Daroussin 				    nlen);				\
230f0957ccaSPeter Wemm 			}						\
231f0957ccaSPeter Wemm 			errno = 0;					\
232c271fa92SBaptiste Daroussin 			ret = iconv(id, (iconv_src_t)&bp, lenp, &obp,	\
233c271fa92SBaptiste Daroussin 			    &outleft);					\
234f0957ccaSPeter Wemm 			if (ret == -1 && errno != E2BIG)		\
235f0957ccaSPeter Wemm 				goto err;				\
236f0957ccaSPeter Wemm 			offset = cw->blen1 - outleft;			\
237f0957ccaSPeter Wemm 		} while (ret != 0); 					\
238f0957ccaSPeter Wemm 	} while (0)
239f0957ccaSPeter Wemm #else
240f0957ccaSPeter Wemm #define CONVERT2(_buffer, lenp, cw, offset)
241f0957ccaSPeter Wemm #endif
242f0957ccaSPeter Wemm 
243f0957ccaSPeter Wemm 
244*110d525eSBaptiste Daroussin 	memset(&mbs, 0, sizeof(mbs));
245f0957ccaSPeter Wemm 	BINC_RETC(NULL, *tostr, *blen, nlen);
246f0957ccaSPeter Wemm 	dst = *tostr; buflen = *blen;
247f0957ccaSPeter Wemm 
248f0957ccaSPeter Wemm #ifdef USE_ICONV
249f0957ccaSPeter Wemm 	if (id != (iconv_t)-1) {
250f0957ccaSPeter Wemm 		dst = buffer; buflen = CONV_BUFFER_SIZE;
251f0957ccaSPeter Wemm 	}
252f0957ccaSPeter Wemm #endif
253f0957ccaSPeter Wemm 
254f0957ccaSPeter Wemm 	for (i = 0, j = 0; i < len; ++i) {
255f0957ccaSPeter Wemm 		n = wcrtomb(dst+j, str[i], &mbs);
256c271fa92SBaptiste Daroussin 		if (n == -1)
257c271fa92SBaptiste Daroussin 			goto err;
258f0957ccaSPeter Wemm 		j += n;
259f0957ccaSPeter Wemm 		if (buflen < j + MB_CUR_MAX) {
260f0957ccaSPeter Wemm 			if (id != (iconv_t)-1) {
261f0957ccaSPeter Wemm 				CONVERT2(buffer, &j, cw, offset);
262f0957ccaSPeter Wemm 			} else {
263f0957ccaSPeter Wemm 				nlen += 256;
264f0957ccaSPeter Wemm 				BINC_RETC(NULL, *tostr, *blen, nlen);
265f0957ccaSPeter Wemm 				dst = *tostr; buflen = *blen;
266f0957ccaSPeter Wemm 			}
267f0957ccaSPeter Wemm 		}
268f0957ccaSPeter Wemm 	}
269f0957ccaSPeter Wemm 
270f0957ccaSPeter Wemm 	n = wcrtomb(dst+j, L'\0', &mbs);
271f0957ccaSPeter Wemm 	j += n - 1;				/* don't count NUL at the end */
272f0957ccaSPeter Wemm 	*tolen = j;
273f0957ccaSPeter Wemm 
274f0957ccaSPeter Wemm 	if (id != (iconv_t)-1) {
275f0957ccaSPeter Wemm 		CONVERT2(buffer, &j, cw, offset);
276c271fa92SBaptiste Daroussin 		/* back to the initial state */
277c271fa92SBaptiste Daroussin 		CONVERT2(NULL, NULL, cw, offset);
278f0957ccaSPeter Wemm 		*tolen = offset;
279f0957ccaSPeter Wemm 	}
280f0957ccaSPeter Wemm 
281f0957ccaSPeter Wemm 	error = 0;
282f0957ccaSPeter Wemm err:
283f0957ccaSPeter Wemm 	if (error)
284f0957ccaSPeter Wemm 		*tolen = j;
285f0957ccaSPeter Wemm 	*pdst = cw->bp1.c;
286f0957ccaSPeter Wemm 	IC_RESET();
287f0957ccaSPeter Wemm 
288f0957ccaSPeter Wemm 	return error;
289f0957ccaSPeter Wemm }
290f0957ccaSPeter Wemm 
291f0957ccaSPeter Wemm static int
fe_int2char(SCR * sp,const CHAR_T * str,ssize_t len,CONVWIN * cw,size_t * tolen,char ** dst)292f0957ccaSPeter Wemm fe_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
293f0957ccaSPeter Wemm     size_t *tolen, char **dst)
294f0957ccaSPeter Wemm {
295f0957ccaSPeter Wemm 	return default_int2char(sp, str, len, cw, tolen, dst,
296f0957ccaSPeter Wemm 		sp->conv.id[IC_FE_INT2CHAR]);
297f0957ccaSPeter Wemm }
298f0957ccaSPeter Wemm 
299f0957ccaSPeter Wemm static int
cs_int2char(SCR * sp,const CHAR_T * str,ssize_t len,CONVWIN * cw,size_t * tolen,char ** dst)300f0957ccaSPeter Wemm cs_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
301f0957ccaSPeter Wemm     size_t *tolen, char **dst)
302f0957ccaSPeter Wemm {
303c271fa92SBaptiste Daroussin 	return default_int2char(sp, str, len, cw, tolen, dst, (iconv_t)-1);
304f0957ccaSPeter Wemm }
305f0957ccaSPeter Wemm 
306f0957ccaSPeter Wemm #endif
307f0957ccaSPeter Wemm 
308f0957ccaSPeter Wemm /*
309f0957ccaSPeter Wemm  * conv_init --
310f0957ccaSPeter Wemm  *	Initialize the iconv environment.
311f0957ccaSPeter Wemm  *
312c271fa92SBaptiste Daroussin  * PUBLIC: void conv_init(SCR *, SCR *);
313f0957ccaSPeter Wemm  */
314f0957ccaSPeter Wemm void
conv_init(SCR * orig,SCR * sp)315f0957ccaSPeter Wemm conv_init(SCR *orig, SCR *sp)
316f0957ccaSPeter Wemm {
317f0957ccaSPeter Wemm 	int i;
318f0957ccaSPeter Wemm 
319f0957ccaSPeter Wemm 	if (orig == NULL)
320f0957ccaSPeter Wemm 		setlocale(LC_ALL, "");
321f0957ccaSPeter Wemm 	if (orig != NULL)
322*110d525eSBaptiste Daroussin 		memmove(&sp->conv, &orig->conv, sizeof(CONV));
323f0957ccaSPeter Wemm #ifdef USE_WIDECHAR
324f0957ccaSPeter Wemm 	else {
325f0957ccaSPeter Wemm 		char *ctype = setlocale(LC_CTYPE, NULL);
326f0957ccaSPeter Wemm 
327f0957ccaSPeter Wemm 		/*
328f0957ccaSPeter Wemm 		 * XXX
329f0957ccaSPeter Wemm 		 * This hack fixes the libncursesw issue on FreeBSD.
330f0957ccaSPeter Wemm 		 */
331f0957ccaSPeter Wemm 		if (!strcmp(ctype, "ko_KR.CP949"))
332f0957ccaSPeter Wemm 			setlocale(LC_CTYPE, "ko_KR.eucKR");
333f0957ccaSPeter Wemm 		else if (!strcmp(ctype, "zh_CN.GB2312"))
334f0957ccaSPeter Wemm 			setlocale(LC_CTYPE, "zh_CN.eucCN");
335f0957ccaSPeter Wemm 		else if (!strcmp(ctype, "zh_CN.GBK"))
336f0957ccaSPeter Wemm 			setlocale(LC_CTYPE, "zh_CN.GB18030");
337f0957ccaSPeter Wemm 
338f0957ccaSPeter Wemm 		/*
339f0957ccaSPeter Wemm 		 * Switch to 8bit mode if locale is C;
340f0957ccaSPeter Wemm 		 * LC_CTYPE should be reseted to C if unmatched.
341f0957ccaSPeter Wemm 		 */
342f0957ccaSPeter Wemm 		if (!strcmp(ctype, "C") || !strcmp(ctype, "POSIX")) {
343f0957ccaSPeter Wemm 			sp->conv.sys2int = sp->conv.file2int = raw2int;
344f0957ccaSPeter Wemm 			sp->conv.int2sys = sp->conv.int2file = int2raw;
345f0957ccaSPeter Wemm 			sp->conv.input2int = raw2int;
346f0957ccaSPeter Wemm 		} else {
347f0957ccaSPeter Wemm 			sp->conv.sys2int = cs_char2int;
348f0957ccaSPeter Wemm 			sp->conv.int2sys = cs_int2char;
349f0957ccaSPeter Wemm 			sp->conv.file2int = fe_char2int;
350f0957ccaSPeter Wemm 			sp->conv.int2file = fe_int2char;
351f0957ccaSPeter Wemm 			sp->conv.input2int = ie_char2int;
352f0957ccaSPeter Wemm 		}
353f0957ccaSPeter Wemm #ifdef USE_ICONV
354f0957ccaSPeter Wemm 		o_set(sp, O_INPUTENCODING, OS_STRDUP, codeset(), 0);
355f0957ccaSPeter Wemm #endif
356f0957ccaSPeter Wemm 	}
357f0957ccaSPeter Wemm #endif
358f0957ccaSPeter Wemm 
359f0957ccaSPeter Wemm 	/* iconv descriptors must be distinct to screens. */
360f0957ccaSPeter Wemm 	for (i = 0; i <= IC_IE_TO_UTF16; ++i)
361f0957ccaSPeter Wemm 		sp->conv.id[i] = (iconv_t)-1;
362f0957ccaSPeter Wemm #ifdef USE_ICONV
363f0957ccaSPeter Wemm 	conv_enc(sp, O_INPUTENCODING, 0);
364f0957ccaSPeter Wemm #endif
365f0957ccaSPeter Wemm }
366f0957ccaSPeter Wemm 
367f0957ccaSPeter Wemm /*
368f0957ccaSPeter Wemm  * conv_enc --
369f0957ccaSPeter Wemm  *	Convert file/input encoding.
370f0957ccaSPeter Wemm  *
371c271fa92SBaptiste Daroussin  * PUBLIC: int conv_enc(SCR *, int, char *);
372f0957ccaSPeter Wemm  */
373f0957ccaSPeter Wemm int
conv_enc(SCR * sp,int option,char * enc)374f0957ccaSPeter Wemm conv_enc(SCR *sp, int option, char *enc)
375f0957ccaSPeter Wemm {
376f0957ccaSPeter Wemm #if defined(USE_WIDECHAR) && defined(USE_ICONV)
377f0957ccaSPeter Wemm 	iconv_t *c2w, *w2c;
378c271fa92SBaptiste Daroussin 	iconv_t id_c2w, id_w2c;
379f0957ccaSPeter Wemm 
380f0957ccaSPeter Wemm 	switch (option) {
381f0957ccaSPeter Wemm 	case O_FILEENCODING:
382f0957ccaSPeter Wemm 		c2w = sp->conv.id + IC_FE_CHAR2INT;
383f0957ccaSPeter Wemm 		w2c = sp->conv.id + IC_FE_INT2CHAR;
384c271fa92SBaptiste Daroussin 		if (!enc)
385c271fa92SBaptiste Daroussin 			enc = O_STR(sp, O_FILEENCODING);
386c271fa92SBaptiste Daroussin 
387f0957ccaSPeter Wemm 		if (strcasecmp(codeset(), enc)) {
388c271fa92SBaptiste Daroussin 			if ((id_c2w = iconv_open(codeset(), enc)) ==
389c271fa92SBaptiste Daroussin 			    (iconv_t)-1)
390f0957ccaSPeter Wemm 				goto err;
391c271fa92SBaptiste Daroussin 			if ((id_w2c = iconv_open(enc, codeset())) ==
392c271fa92SBaptiste Daroussin 			    (iconv_t)-1)
393f0957ccaSPeter Wemm 				goto err;
394c271fa92SBaptiste Daroussin 		} else {
395c271fa92SBaptiste Daroussin 			id_c2w = (iconv_t)-1;
396c271fa92SBaptiste Daroussin 			id_w2c = (iconv_t)-1;
397c271fa92SBaptiste Daroussin 		}
398c271fa92SBaptiste Daroussin 
399f0957ccaSPeter Wemm 		break;
400c271fa92SBaptiste Daroussin 
401f0957ccaSPeter Wemm 	case O_INPUTENCODING:
402f0957ccaSPeter Wemm 		c2w = sp->conv.id + IC_IE_CHAR2INT;
403f0957ccaSPeter Wemm 		w2c = sp->conv.id + IC_IE_TO_UTF16;
404c271fa92SBaptiste Daroussin 		if (!enc)
405c271fa92SBaptiste Daroussin 			enc = O_STR(sp, O_INPUTENCODING);
406c271fa92SBaptiste Daroussin 
407c271fa92SBaptiste Daroussin 		if (strcasecmp(codeset(), enc)) {
408c271fa92SBaptiste Daroussin 			if ((id_c2w = iconv_open(codeset(), enc)) ==
409c271fa92SBaptiste Daroussin 			    (iconv_t)-1)
410c271fa92SBaptiste Daroussin 				goto err;
411c271fa92SBaptiste Daroussin 		} else
412c271fa92SBaptiste Daroussin 			id_c2w = (iconv_t)-1;
413c271fa92SBaptiste Daroussin 
414c271fa92SBaptiste Daroussin 		/* UTF-16 can not be locale and can not be inputed. */
415c271fa92SBaptiste Daroussin 		if ((id_w2c = iconv_open("utf-16be", enc)) == (iconv_t)-1)
416c271fa92SBaptiste Daroussin 			goto err;
417c271fa92SBaptiste Daroussin 
418c271fa92SBaptiste Daroussin 		break;
419c271fa92SBaptiste Daroussin 
420c271fa92SBaptiste Daroussin 	default:
421c271fa92SBaptiste Daroussin 		abort();
422c271fa92SBaptiste Daroussin 	}
423c271fa92SBaptiste Daroussin 
424f0957ccaSPeter Wemm 	if (*c2w != (iconv_t)-1)
425f0957ccaSPeter Wemm 		iconv_close(*c2w);
426f0957ccaSPeter Wemm 	if (*w2c != (iconv_t)-1)
427f0957ccaSPeter Wemm 		iconv_close(*w2c);
428c271fa92SBaptiste Daroussin 
429c271fa92SBaptiste Daroussin 	*c2w = id_c2w;
430c271fa92SBaptiste Daroussin 	*w2c = id_w2c;
431f0957ccaSPeter Wemm 
432f0957ccaSPeter Wemm 	F_CLR(sp, SC_CONV_ERROR);
433f0957ccaSPeter Wemm 	F_SET(sp, SC_SCR_REFORMAT);
434f0957ccaSPeter Wemm 
435f0957ccaSPeter Wemm 	return 0;
436f0957ccaSPeter Wemm err:
437f0957ccaSPeter Wemm #endif
438f0957ccaSPeter Wemm 	switch (option) {
439f0957ccaSPeter Wemm 	case O_FILEENCODING:
440c271fa92SBaptiste Daroussin 		msgq(sp, M_ERR, "321|File encoding conversion not supported");
441f0957ccaSPeter Wemm 		break;
442f0957ccaSPeter Wemm 	case O_INPUTENCODING:
443c271fa92SBaptiste Daroussin 		msgq(sp, M_ERR, "322|Input encoding conversion not supported");
444f0957ccaSPeter Wemm 		break;
445f0957ccaSPeter Wemm 	}
446f0957ccaSPeter Wemm 	return 1;
447f0957ccaSPeter Wemm }
448f0957ccaSPeter Wemm 
449f0957ccaSPeter Wemm /*
450f0957ccaSPeter Wemm  * conv_end --
451f0957ccaSPeter Wemm  *	Close the iconv descriptors, release the buffer.
452f0957ccaSPeter Wemm  *
453c271fa92SBaptiste Daroussin  * PUBLIC: void conv_end(SCR *);
454f0957ccaSPeter Wemm  */
455f0957ccaSPeter Wemm void
conv_end(SCR * sp)456f0957ccaSPeter Wemm conv_end(SCR *sp)
457f0957ccaSPeter Wemm {
458f0957ccaSPeter Wemm #if defined(USE_WIDECHAR) && defined(USE_ICONV)
459f0957ccaSPeter Wemm 	int i;
460f0957ccaSPeter Wemm 	for (i = 0; i <= IC_IE_TO_UTF16; ++i)
461f0957ccaSPeter Wemm 		if (sp->conv.id[i] != (iconv_t)-1)
462f0957ccaSPeter Wemm 			iconv_close(sp->conv.id[i]);
463f0957ccaSPeter Wemm 	free(sp->cw.bp1.c);
464f0957ccaSPeter Wemm #endif
465f0957ccaSPeter Wemm }
466