guard against Solaris preprocessor polution
[nvi.git] / common / conv.c
blob550ab084097c4d58c5cd36b82c045ea62bb434f5
1 /*-
2 * Copyright (c) 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1993, 1994, 1995, 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: conv.c,v 1.15 2001/05/13 09:05:06 skimo Exp $ (Berkeley) $Date: 2001/05/13 09:05:06 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
20 #include <bitstring.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
28 #include "common.h"
29 #ifdef HAVE_NCURSESW
30 #include <ncurses.h>
31 #endif
33 #include <langinfo.h>
34 #include <iconv.h>
35 #include <locale.h>
37 int
38 raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, size_t *tolen,
39 CHAR_T **dst)
41 int i;
42 CHAR_T **tostr = (CHAR_T **)&cw->bp1;
43 size_t *blen = &cw->blen1;
45 BINC_RETW(NULL, *tostr, *blen, len);
47 *tolen = len;
48 for (i = 0; i < len; ++i)
49 (*tostr)[i] = (u_char) str[i];
51 *dst = cw->bp1;
53 return 0;
56 #define CONV_BUFFER_SIZE 512
57 /* fill the buffer with codeset encoding of string pointed to by str
58 * left has the number of bytes left in str and is adjusted
59 * len contains the number of bytes put in the buffer
61 #define CONVERT(str, left, src, len) \
62 do { \
63 size_t outleft; \
64 char *bp = buffer; \
65 outleft = CONV_BUFFER_SIZE; \
66 errno = 0; \
67 if (iconv(id, (char **)&str, &left, &bp, &outleft) == -1 && \
68 errno != E2BIG) \
69 goto err; \
70 len = CONV_BUFFER_SIZE - outleft; \
71 src = buffer; \
72 } while (0)
74 int
75 default_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
76 size_t *tolen, CHAR_T **dst)
78 int i = 0, j;
79 CHAR_T **tostr = (CHAR_T **)&cw->bp1;
80 size_t *blen = &cw->blen1;
81 mbstate_t mbs;
82 size_t n;
83 ssize_t nlen = len;
84 char *src = (char *)str;
85 iconv_t id = (iconv_t)-1;
86 char *enc = O_STR(sp, O_FILEENCODING);
87 char buffer[CONV_BUFFER_SIZE];
88 size_t left = len;
90 MEMSET(&mbs, 0, 1);
91 BINC_RETW(NULL, *tostr, *blen, nlen);
93 if (strcmp(nl_langinfo(CODESET), enc)) {
94 id = iconv_open(nl_langinfo(CODESET), enc);
95 if (id == (iconv_t)-1)
96 goto err;
97 CONVERT(str, left, src, len);
100 for (i = 0, j = 0; j < len; ) {
101 n = mbrtowc((*tostr)+i, src+j, len-j, &mbs);
102 /* NULL character converted */
103 if (n == -1 || n == -2) goto err;
104 if (n == 0) n = 1;
105 j += n;
106 if (++i >= *blen) {
107 nlen += 256;
108 BINC_RETW(NULL, *tostr, *blen, nlen);
110 if (id != (iconv_t)-1 && j == len && left) {
111 CONVERT(str, left, src, len);
112 j = 0;
115 *tolen = i;
117 if (id != (iconv_t)-1)
118 iconv_close(id);
120 *dst = cw->bp1;
122 return 0;
123 err:
124 *tolen = i;
125 if (id != (iconv_t)-1)
126 iconv_close(id);
127 *dst = cw->bp1;
129 return 1;
132 int
133 CHAR_T_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
134 size_t *tolen, char **dst)
136 *tolen = len * sizeof(CHAR_T);
137 *dst = (char*) str;
139 return 0;
142 int
143 CHAR_T_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw,
144 size_t *tolen, CHAR_T **dst)
146 *tolen = len / sizeof(CHAR_T);
147 *dst = (CHAR_T*) str;
149 return 0;
152 int
153 int2raw(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, size_t *tolen,
154 char **dst)
156 int i;
157 char **tostr = (char **)&cw->bp1;
158 size_t *blen = &cw->blen1;
160 BINC_RET(NULL, *tostr, *blen, len);
162 *tolen = len;
163 for (i = 0; i < len; ++i)
164 (*tostr)[i] = str[i];
166 *dst = cw->bp1;
168 return 0;
171 int
172 default_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
173 size_t *tolen, char **pdst)
175 int i, j, offset = 0;
176 char **tostr = (char **)&cw->bp1;
177 size_t *blen = &cw->blen1;
178 mbstate_t mbs;
179 size_t n;
180 ssize_t nlen = len + MB_CUR_MAX;
181 char *dst;
182 size_t buflen;
183 char buffer[CONV_BUFFER_SIZE];
184 iconv_t id = (iconv_t)-1;
185 char *enc = O_STR(sp, O_FILEENCODING);
187 /* convert first len bytes of buffer and append it to cw->bp
188 * len is adjusted => 0
189 * offset contains the offset in cw->bp and is adjusted
190 * cw->bp is grown as required
192 #define CONVERT2(len, cw, offset) \
193 do { \
194 char *bp = buffer; \
195 while (len != 0) { \
196 size_t outleft = cw->blen1 - offset; \
197 char *obp = (char *)cw->bp1 + offset; \
198 if (cw->blen1 < offset + MB_CUR_MAX) { \
199 nlen += 256; \
200 BINC_RET(NULL, cw->bp1, cw->blen1, nlen); \
202 errno = 0; \
203 if (iconv(id, &bp, &len, &obp, &outleft) == -1 && \
204 errno != E2BIG) \
205 goto err; \
206 offset = cw->blen1 - outleft; \
208 } while (0)
211 MEMSET(&mbs, 0, 1);
212 BINC_RET(NULL, *tostr, *blen, nlen);
213 dst = *tostr; buflen = *blen;
215 if (strcmp(nl_langinfo(CODESET), enc)) {
216 id = iconv_open(enc, nl_langinfo(CODESET));
217 if (id == (iconv_t)-1)
218 goto err;
219 dst = buffer; buflen = CONV_BUFFER_SIZE;
222 for (i = 0, j = 0; i < len; ++i) {
223 n = wcrtomb(dst+j, str[i], &mbs);
224 if (n == -1) goto err;
225 j += n;
226 if (buflen < j + MB_CUR_MAX) {
227 if (id != (iconv_t)-1) {
228 CONVERT2(j, cw, offset);
229 } else {
230 nlen += 256;
231 BINC_RET(NULL, *tostr, *blen, nlen);
232 dst = *tostr; buflen = *blen;
237 n = wcrtomb(dst+j, L'\0', &mbs);
238 j += n - 1; /* don't count NUL at the end */
239 *tolen = j;
241 if (id != (iconv_t)-1) {
242 CONVERT2(j, cw, offset);
243 *tolen = offset;
246 *pdst = cw->bp1;
248 return 0;
249 err:
250 *tolen = j;
252 *pdst = cw->bp1;
254 return 1;
257 #ifdef HAVE_ADDNWSTR
258 int
259 default_int2disp (SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
260 size_t *tolen, char **dst)
262 int i, j;
263 chtype *dest;
264 char **tostr = (char **)&cw->bp1;
265 size_t *blen = &cw->blen1;
267 BINC_RET(NULL, *tostr, *blen, len * sizeof(chtype));
269 dest = *tostr;
271 for (i = 0, j = 0; i < len; ++i)
272 if (str[i] > 0xffff) {
273 dest[j++] = 0xfffd;
274 } else
275 dest[j++] = str[i];
276 *tolen = j;
278 *dst = cw.bp1;
280 return 0;
283 #else
285 int
286 default_int2disp (SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw,
287 size_t *tolen, char **dst)
289 int i, j;
290 char **tostr = (char **)&cw->bp1;
291 size_t *blen = &cw->blen1;
293 BINC_RET(NULL, *tostr, *blen, len * 2);
295 for (i = 0, j = 0; i < len; ++i)
296 if (CHAR_WIDTH(NULL, str[i]) > 1) {
297 (*tostr)[j++] = '[';
298 (*tostr)[j++] = ']';
299 } else
300 (*tostr)[j++] = str[i];
301 *tolen = j;
303 *dst = cw->bp1;
305 return 0;
307 #endif
310 void
311 conv_init (SCR *orig, SCR *sp)
313 if (orig != NULL)
314 MEMCPY(&sp->conv, &orig->conv, 1);
315 else {
316 setlocale(LC_ALL, "");
317 sp->conv.char2int = raw2int;
318 sp->conv.int2char = int2raw;
319 sp->conv.file2int = default_char2int;
320 sp->conv.int2file = default_int2char;
321 sp->conv.int2disp = default_int2disp;
322 o_set(sp, O_FILEENCODING, OS_STRDUP, nl_langinfo(CODESET), 0);
327 conv_enc (SCR *sp, char *enc)
329 iconv_t id;
331 if (!*enc) {
332 sp->conv.file2int = raw2int;
333 sp->conv.int2file = int2raw;
334 return 0;
337 if (!strcmp(enc, "WCHAR_T")) {
338 sp->conv.file2int = CHAR_T_char2int;
339 sp->conv.int2file = CHAR_T_int2char;
340 return 0;
343 id = iconv_open(enc, nl_langinfo(CODESET));
344 if (id == (iconv_t)-1)
345 goto err;
346 iconv_close(id);
347 id = iconv_open(nl_langinfo(CODESET), enc);
348 if (id == (iconv_t)-1)
349 goto err;
350 iconv_close(id);
352 sp->conv.file2int = default_char2int;
353 sp->conv.int2file = default_int2char;
355 F_CLR(sp, SC_CONV_ERROR);
356 F_SET(sp, SC_SCR_REFORMAT);
358 return 0;
359 err:
360 msgq(sp, M_ERR,
361 "321|File encoding conversion not supported");
362 return 1;