2
* Copyright 2002, 2003, 2004, 2005 by Paul Mattes.
3
* Permission to use, copy, modify, and distribute this software and its
4
* documentation for any purpose and without fee is hereby granted,
5
* provided that the above copyright notice appear in all copies and that
6
* both that copyright notice and this permission notice appear in
7
* supporting documentation.
9
* x3270 is distributed in the hope that it will be useful, but WITHOUT ANY
10
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
* FOR A PARTICULAR PURPOSE. See the file LICENSE for more details.
16
* A 3270 Terminal Emulator for X11
17
* Wide character translation functions.
26
#if !defined(PR3287) /*[*/
32
#include "trace_dsc.h"
33
#if !defined(PR3287) /*[*/
39
#define ICU_DATA "ICU_DATA"
41
char *local_encoding = CN;
43
static UConverter *dbcs_converter = NULL;
44
static char *dbcs_converter_name = CN;
45
static UConverter *sbcs_converter = NULL;
46
static char *sbcs_converter_name = CN;
47
static UConverter *local_converter = NULL;
48
#if defined(X3270_DISPLAY) /*[*/
49
static UConverter *wdisplay_converter = NULL;
51
static Boolean same_converter = False;
53
/* Initialize, or reinitialize the EBCDIC DBCS converters. */
55
wide_init(char *converter_names, char *local_name)
57
UErrorCode err = U_ZERO_ERROR;
59
Boolean lib_ok = False;
60
Boolean dot_ok = False;
61
char *cn_copy, *buf, *token;
62
char *sbcs_converters = NULL;
63
char *dbcs_converters = NULL;
64
int n_converter_sets = 0;
65
int n_sbcs_converters = 0;
66
int n_dbcs_converters = 0;
68
/* This may be a reinit. */
69
if (local_converter != NULL) {
70
ucnv_close(local_converter);
71
local_converter = NULL;
73
Replace(local_encoding, CN);
74
if (sbcs_converter != NULL) {
75
ucnv_close(sbcs_converter);
76
sbcs_converter = NULL;
78
Replace(sbcs_converter_name, CN);
79
if (dbcs_converter != NULL) {
80
ucnv_close(dbcs_converter);
81
dbcs_converter = NULL;
83
Replace(dbcs_converter_name, CN);
84
#if defined(X3270_DISPLAY) /*[*/
85
if (wdisplay_converter != NULL) {
86
ucnv_close(wdisplay_converter);
87
wdisplay_converter = NULL;
90
same_converter = False;
92
/* Make sure that $ICU_DATA has LIBX3270DIR and . in it. */
93
cur_path = getenv(ICU_DATA);
95
char *t = NewString(cur_path);
99
while (!(lib_ok && dot_ok) &&
100
(token = strtok(buf, ":")) != CN) {
102
if (!strcmp(token, LIBX3270DIR)) {
104
} else if (!strcmp(token, ".")) {
110
if (!lib_ok || !dot_ok) {
113
s = new_path = Malloc(strlen(ICU_DATA) +
114
(cur_path? strlen(cur_path): 0) +
115
strlen(LIBX3270DIR) + 5 /* ICU_DATA=*:*:.\n */);
117
s += sprintf(s, "%s=", ICU_DATA);
119
s += sprintf(s, "%s", cur_path);
121
if (s[-1] != '=' && s[-1] != ':')
123
s += sprintf(s, "%s", LIBX3270DIR);
126
if (s[-1] != '=' && s[-1] != ':')
131
if (putenv(new_path) < 0) {
132
popup_an_errno(errno, "putenv for " ICU_DATA " failed");
137
/* Decode local converter name. */
138
if (local_name == CN) {
139
(void) setlocale(LC_CTYPE, "");
140
local_name = nl_langinfo(CODESET);
142
if (local_name != CN) {
144
local_converter = ucnv_open(local_name, &err);
145
if (local_converter == NULL) {
146
popup_an_error("Cannot find ICU converter for "
147
"local encoding:\n%s",
150
Replace(local_encoding, NewString(local_name));
153
/* Decode host and display converter names. */
154
if (converter_names == CN)
158
* Split into SBCS and DBCS converters, separated by '+'. If only one
159
* converter is specified, it's the DBCS converter.
161
n_converter_sets = 0;
162
buf = cn_copy = NewString(converter_names);
163
while ((token = strtok(buf, "+")) != CN) {
165
switch (n_converter_sets) {
166
case 0: /* DBCS or SBCS */
167
dbcs_converters = token;
170
sbcs_converters = dbcs_converters;
171
dbcs_converters = token;
174
popup_an_error("Extra converter set '%s' ignored", token);
180
if (sbcs_converters != NULL) {
181
n_sbcs_converters = 0;
182
buf = sbcs_converters;
183
while ((token = strtok(buf, ",")) != CN) {
185
switch (n_sbcs_converters) {
188
sbcs_converter = ucnv_open(token, &err);
189
if (sbcs_converter == NULL) {
190
popup_an_error("Cannot find ICU converter "
191
"for host SBCS:\n%s", token);
195
Replace(sbcs_converter_name, NewString(token));
198
popup_an_error("Extra converter name '%s' ignored",
206
if (dbcs_converters != NULL) {
207
n_dbcs_converters = 0;
208
buf = dbcs_converters;
209
while ((token = strtok(buf, ",")) != CN) {
211
switch (n_dbcs_converters) {
214
dbcs_converter = ucnv_open(token, &err);
215
if (dbcs_converter == NULL) {
216
popup_an_error("Cannot find ICU converter "
217
"for host DBCS:\n%s", token);
221
Replace(dbcs_converter_name, NewString(token));
223
case 1: /* display */
224
#if defined(X3270_DISPLAY) /*[*/
226
wdisplay_converter = ucnv_open(token, &err);
227
if (wdisplay_converter == NULL) {
228
popup_an_error("Cannot find ICU converter "
229
"for display DBCS:\n%s", token);
236
popup_an_error("Extra converter name '%s' ignored",
246
if (n_dbcs_converters < 2) {
247
popup_an_error("Missing DBCS converter value");
250
if (dbcs_converter_name != CN &&
251
sbcs_converter_name != CN &&
252
!strcmp(dbcs_converter_name, sbcs_converter_name)) {
253
same_converter = True;
260
xlate1(unsigned char from0, unsigned char from1, unsigned char to_buf[],
261
UConverter *from_cnv, const char *from_name,
262
UConverter *to_cnv, const char *to_name)
264
UErrorCode err = U_ZERO_ERROR;
270
#if defined(WIDE_DEBUG) /*[*/
274
/* Do something reasonable in case of failure. */
275
to_buf[0] = to_buf[1] = 0;
277
/* Convert string from source to Unicode. */
278
if (same_converter) {
279
from_buf[0] = EBC_so;
282
from_buf[3] = EBC_si;
289
len = ucnv_toUChars(from_cnv, Ubuf, 2, from_buf, from_len, &err);
290
if (err != U_ZERO_ERROR) {
291
trace_ds("[%s toUnicode of DBCS X'%02x%02x' failed, ICU "
292
"error %d]\n", from_name, from0, from1, (int)err);
295
if (Ubuf[0] == 0xfffd) {
296
/* No translation. */
297
trace_ds("[%s toUnicode of DBCS X'%02x%02x' failed]\n",
298
from_name, from0, from1);
301
#if defined(WIDE_DEBUG) /*[*/
302
printf("Got Unicode %x\n", Ubuf[0]);
305
if (to_cnv != NULL) {
306
/* Convert string from Unicode to Destination. */
307
len = ucnv_fromUChars(to_cnv, tmp_to_buf, 3, Ubuf, len, &err);
308
if (err != U_ZERO_ERROR) {
309
trace_ds("[fromUnicode of U+%04x to %s failed, ICU "
310
"error %d]\n", Ubuf[0], to_name, (int)err);
313
to_buf[0] = tmp_to_buf[0];
314
to_buf[1] = tmp_to_buf[1];
315
#if defined(WIDE_DEBUG) /*[*/
316
printf("Got %u %s characters:", len, to_name);
317
for (i = 0; i < len; i++) {
318
printf(" %02x", to_buf[i]);
323
to_buf[0] = (Ubuf[0] >> 8) & 0xff;
324
to_buf[1] = Ubuf[0] & 0xff;
328
#if defined(X3270_DISPLAY) /*[*/
329
/* Translate a DBCS EBCDIC character to a display character. */
331
dbcs_to_display(unsigned char ebc1, unsigned char ebc2, unsigned char c[])
333
xlate1(ebc1, ebc2, c, dbcs_converter, "host DBCS", wdisplay_converter,
338
/* Translate a DBCS EBCDIC character to a 2-byte Unicode character. */
340
dbcs_to_unicode16(unsigned char ebc1, unsigned char ebc2, unsigned char c[])
342
xlate1(ebc1, ebc2, c, dbcs_converter, "host DBCS", NULL, NULL);
346
* Translate a DBCS EBCDIC character to a local multi-byte character.
347
* Returns -1 for error, or the mb length. NULL terminates.
350
dbcs_to_mb(unsigned char ebc1, unsigned char ebc2, char *mb)
352
UErrorCode err = U_ZERO_ERROR;
357
if (local_converter == NULL) {
363
/* Translate to Unicode first. */
364
dbcs_to_unicode16(ebc1, ebc2, w);
365
Ubuf = (w[0] << 8) | w[1];
367
/* Then translate to the local encoding. */
368
len = ucnv_fromUChars(local_converter, mb, 16, &Ubuf, 1, &err);
369
if (err != U_ZERO_ERROR) {
370
trace_ds("[fromUnicode of U+%04x to local failed, ICU "
371
"error %d]\n", Ubuf, (int)err);
378
* Translate an SBCS EBCDIC character to a local multi-byte character.
379
* Returns -1 for error, or the mb length. NULL terminates.
382
sbcs_to_mb(unsigned char ebc, char *mb)
384
UErrorCode err = U_ZERO_ERROR;
388
if (sbcs_converter == NULL) {
389
/* No SBCS converter, do EBCDIC to latin-1. */
390
if (local_converter == NULL) {
391
/* No local converter either, latin-1 is it. */
397
/* Have a local converter; use it below. */
400
/* Have an SBCS converter. Convert from SBCS to Unicode. */
402
len = ucnv_toUChars(sbcs_converter, &Ubuf, 1, (char *)&ebc, 1,
404
if (err != U_ZERO_ERROR &&
405
err != U_STRING_NOT_TERMINATED_WARNING) {
406
trace_ds("[toUChars failed, ICU error %d]\n",
412
/* Convert from Unicode to the local encoding. */
413
len = ucnv_fromUChars(local_converter, mb, 16, &Ubuf, 1, &err);
414
if (err != U_ZERO_ERROR) {
415
trace_ds("[fromUnicode of U+%04x to local failed, ICU "
416
"error %d]\n", Ubuf, (int)err);
423
* Translate a local multi-byte string to Unicode characters.
424
* Returns -1 for error, or the length. NULL terminates.
427
mb_to_unicode(char *mb, int mblen, UChar *u, int ulen, UErrorCode *err)
429
UErrorCode local_err;
431
Boolean print_errs = False;
433
if (local_converter == NULL) {
436
for (i = 0; i < mblen; i++) {
446
len = ucnv_toUChars(local_converter, u, ulen, mb, mblen, err);
447
if (*err != U_ZERO_ERROR && *err != U_STRING_NOT_TERMINATED_WARNING) {
449
trace_ds("[toUChars failed, ICU error %d]\n",
457
* Try to map a Unicode character to the Host SBCS character set.
458
* Returns ASCII in cp[0].
461
dbcs_map8(UChar u, unsigned char *cp)
463
UErrorCode err = U_ZERO_ERROR;
470
if (sbcs_converter != NULL) {
471
len = ucnv_fromUChars(sbcs_converter, (char *)cp, 1, &u, 1,
473
if ((err != U_ZERO_ERROR &&
474
err != U_STRING_NOT_TERMINATED_WARNING) ||
475
(*cp == '?' && u != '?')) {
485
* Try to map a Unicode character to the Host DBCS character set.
486
* Returns EBCDIC in cp[].
489
dbcs_map16(UChar u, unsigned char *cp)
491
UErrorCode err = U_ZERO_ERROR;
494
if (same_converter) {
497
len = ucnv_fromUChars(dbcs_converter, tmp_cp, 5, &u, 1, &err);
498
if (err != U_ZERO_ERROR ||
506
len = ucnv_fromUChars(dbcs_converter, (char *)cp, 2, &u, 1,
508
return (err == U_ZERO_ERROR ||
509
err == U_STRING_NOT_TERMINATED_WARNING);