~ubuntu-branches/ubuntu/natty/ibm-3270/natty

« back to all changes in this revision

Viewing changes to s3270/wide.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2009-12-14 11:48:53 UTC
  • mfrom: (1.1.4 upstream) (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20091214114853-mywixml32hct9jr1
Tags: 3.3.10ga4-2
* Fix section to match override.
* Use debhelper compat level 7.
* Use 3.0 (quilt) source format.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
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.
8
 
 *
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.
12
 
 */
13
 
 
14
 
/*
15
 
 *      wide.c
16
 
 *              A 3270 Terminal Emulator for X11
17
 
 *              Wide character translation functions.
18
 
 */
19
 
 
20
 
#include "globals.h"
21
 
#include <errno.h>
22
 
#include <locale.h>
23
 
#include <langinfo.h>
24
 
 
25
 
#include "3270ds.h"
26
 
#if !defined(PR3287) /*[*/
27
 
#include "appres.h"
28
 
#endif /*]*/
29
 
 
30
 
#include "popupsc.h"
31
 
#include "tablesc.h"
32
 
#include "trace_dsc.h"
33
 
#if !defined(PR3287) /*[*/
34
 
#include "utilc.h"
35
 
#endif /*]*/
36
 
 
37
 
#include "widec.h"
38
 
 
39
 
#define ICU_DATA        "ICU_DATA"
40
 
 
41
 
char *local_encoding = CN;
42
 
 
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;
50
 
#endif /*]*/
51
 
static Boolean same_converter = False;
52
 
 
53
 
/* Initialize, or reinitialize the EBCDIC DBCS converters. */
54
 
int
55
 
wide_init(char *converter_names, char *local_name)
56
 
{
57
 
        UErrorCode err = U_ZERO_ERROR;
58
 
        char *cur_path = CN;
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;
67
 
 
68
 
        /* This may be a reinit. */
69
 
        if (local_converter != NULL) {
70
 
                ucnv_close(local_converter);
71
 
                local_converter = NULL;
72
 
        }
73
 
        Replace(local_encoding, CN);
74
 
        if (sbcs_converter != NULL) {
75
 
                ucnv_close(sbcs_converter);
76
 
                sbcs_converter = NULL;
77
 
        }
78
 
        Replace(sbcs_converter_name, CN);
79
 
        if (dbcs_converter != NULL) {
80
 
                ucnv_close(dbcs_converter);
81
 
                dbcs_converter = NULL;
82
 
        }
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;
88
 
        }
89
 
#endif /*]*/
90
 
        same_converter = False;
91
 
 
92
 
        /* Make sure that $ICU_DATA has LIBX3270DIR and . in it. */
93
 
        cur_path = getenv(ICU_DATA);
94
 
        if (cur_path != CN) {
95
 
                char *t = NewString(cur_path);
96
 
                char *token;
97
 
                char *buf = t;
98
 
 
99
 
                while (!(lib_ok && dot_ok) &&
100
 
                       (token = strtok(buf, ":")) != CN) {
101
 
                        buf = CN;
102
 
                        if (!strcmp(token, LIBX3270DIR)) {
103
 
                                lib_ok = True;
104
 
                        } else if (!strcmp(token, ".")) {
105
 
                                dot_ok = True;
106
 
                        }
107
 
                }
108
 
                Free(t);
109
 
        }
110
 
        if (!lib_ok || !dot_ok) {
111
 
                char *s, *new_path;
112
 
 
113
 
                s = new_path = Malloc(strlen(ICU_DATA) +
114
 
                    (cur_path? strlen(cur_path): 0) + 
115
 
                    strlen(LIBX3270DIR) + 5 /* ICU_DATA=*:*:.\n */);
116
 
 
117
 
                s += sprintf(s, "%s=", ICU_DATA);
118
 
                if (cur_path != CN)
119
 
                        s += sprintf(s, "%s", cur_path);
120
 
                if (!lib_ok) {
121
 
                        if (s[-1] != '=' && s[-1] != ':')
122
 
                                *s++ = ':';
123
 
                        s += sprintf(s, "%s", LIBX3270DIR);
124
 
                }
125
 
                if (!dot_ok) {
126
 
                        if (s[-1] != '=' && s[-1] != ':')
127
 
                                *s++ = ':';
128
 
                        *s++ = '.';
129
 
                }
130
 
                *s = '\0';
131
 
                if (putenv(new_path) < 0) {
132
 
                        popup_an_errno(errno, "putenv for " ICU_DATA " failed");
133
 
                        return -1;
134
 
                }
135
 
        }
136
 
 
137
 
        /* Decode local converter name. */
138
 
        if (local_name == CN) {
139
 
                (void) setlocale(LC_CTYPE, "");
140
 
                local_name = nl_langinfo(CODESET);
141
 
        }
142
 
        if (local_name != CN) {
143
 
                err = U_ZERO_ERROR;
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",
148
 
                            local_name);
149
 
                }
150
 
                Replace(local_encoding, NewString(local_name));
151
 
        }
152
 
 
153
 
        /* Decode host and display converter names. */
154
 
        if (converter_names == CN)
155
 
                return 0;
156
 
 
157
 
        /*
158
 
         * Split into SBCS and DBCS converters, separated by '+'.  If only one
159
 
         * converter is specified, it's the DBCS converter.
160
 
         */
161
 
        n_converter_sets = 0;
162
 
        buf = cn_copy = NewString(converter_names);
163
 
        while ((token = strtok(buf, "+")) != CN) {
164
 
                buf = CN;
165
 
                switch (n_converter_sets) {
166
 
                case 0: /* DBCS or SBCS */
167
 
                    dbcs_converters = token;
168
 
                    break;
169
 
                case 1: /* DBCS */
170
 
                    sbcs_converters = dbcs_converters;
171
 
                    dbcs_converters = token;
172
 
                    break;
173
 
                default: /* extra */
174
 
                    popup_an_error("Extra converter set '%s' ignored", token);
175
 
                    break;
176
 
                }
177
 
                n_converter_sets++;
178
 
        }
179
 
 
180
 
        if (sbcs_converters != NULL) {
181
 
                n_sbcs_converters = 0;
182
 
                buf = sbcs_converters;
183
 
                while ((token = strtok(buf, ",")) != CN) {
184
 
                        buf = CN;
185
 
                        switch (n_sbcs_converters) {
186
 
                        case 0: /* EBCDIC */
187
 
                            err = U_ZERO_ERROR;
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);
192
 
                                    Free(cn_copy);
193
 
                                    return -1;
194
 
                            }
195
 
                            Replace(sbcs_converter_name, NewString(token));
196
 
                            break;
197
 
                        default: /* extra */
198
 
                            popup_an_error("Extra converter name '%s' ignored",
199
 
                                token);
200
 
                            break;
201
 
                        }
202
 
                        n_sbcs_converters++;
203
 
                }
204
 
        }
205
 
 
206
 
        if (dbcs_converters != NULL) {
207
 
                n_dbcs_converters = 0;
208
 
                buf = dbcs_converters;
209
 
                while ((token = strtok(buf, ",")) != CN) {
210
 
                        buf = CN;
211
 
                        switch (n_dbcs_converters) {
212
 
                        case 0: /* EBCDIC */
213
 
                            err = U_ZERO_ERROR;
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);
218
 
                                    Free(cn_copy);
219
 
                                    return -1;
220
 
                            }
221
 
                            Replace(dbcs_converter_name, NewString(token));
222
 
                            break;
223
 
                        case 1: /* display */
224
 
#if defined(X3270_DISPLAY) /*[*/
225
 
                            err = U_ZERO_ERROR;
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);
230
 
                                    Free(cn_copy);
231
 
                                    return -1;
232
 
                            }
233
 
#endif /*]*/
234
 
                            break;
235
 
                        default: /* extra */
236
 
                            popup_an_error("Extra converter name '%s' ignored",
237
 
                                token);
238
 
                            break;
239
 
                        }
240
 
                        n_dbcs_converters++;
241
 
                }
242
 
        }
243
 
 
244
 
        Free(cn_copy);
245
 
 
246
 
        if (n_dbcs_converters < 2) {
247
 
                popup_an_error("Missing DBCS converter value");
248
 
                return -1;
249
 
        }
250
 
        if (dbcs_converter_name != CN &&
251
 
            sbcs_converter_name != CN &&
252
 
            !strcmp(dbcs_converter_name, sbcs_converter_name)) {
253
 
                same_converter = True;
254
 
        }
255
 
 
256
 
        return 0;
257
 
}
258
 
 
259
 
static void
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)
263
 
{
264
 
        UErrorCode err = U_ZERO_ERROR;
265
 
        UChar Ubuf[2];
266
 
        char from_buf[4];
267
 
        int from_len;
268
 
        char tmp_to_buf[3];
269
 
        int32_t len;
270
 
#if defined(WIDE_DEBUG) /*[*/
271
 
        int i;
272
 
#endif /*]*/
273
 
 
274
 
        /* Do something reasonable in case of failure. */
275
 
        to_buf[0] = to_buf[1] = 0;
276
 
 
277
 
        /* Convert string from source to Unicode. */
278
 
        if (same_converter) {
279
 
                from_buf[0] = EBC_so;
280
 
                from_buf[1] = from0;
281
 
                from_buf[2] = from1;
282
 
                from_buf[3] = EBC_si;
283
 
                from_len = 4;
284
 
        } else {
285
 
                from_buf[0] = from0;
286
 
                from_buf[1] = from1;
287
 
                from_len = 2;
288
 
        }
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);
293
 
                return;
294
 
        }
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);
299
 
                return;
300
 
        }
301
 
#if defined(WIDE_DEBUG) /*[*/
302
 
        printf("Got Unicode %x\n", Ubuf[0]);
303
 
#endif /*]*/
304
 
 
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);
311
 
                        return;
312
 
                }
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]);
319
 
                }
320
 
                printf("\n");
321
 
#endif /*]*/
322
 
        } else {
323
 
                to_buf[0] = (Ubuf[0] >> 8) & 0xff;
324
 
                to_buf[1] = Ubuf[0] & 0xff;
325
 
        }
326
 
}
327
 
 
328
 
#if defined(X3270_DISPLAY) /*[*/
329
 
/* Translate a DBCS EBCDIC character to a display character. */
330
 
void
331
 
dbcs_to_display(unsigned char ebc1, unsigned char ebc2, unsigned char c[])
332
 
{
333
 
        xlate1(ebc1, ebc2, c, dbcs_converter, "host DBCS", wdisplay_converter,
334
 
            "wide display");
335
 
}
336
 
#endif /*]*/
337
 
 
338
 
/* Translate a DBCS EBCDIC character to a 2-byte Unicode character. */
339
 
void
340
 
dbcs_to_unicode16(unsigned char ebc1, unsigned char ebc2, unsigned char c[])
341
 
{
342
 
        xlate1(ebc1, ebc2, c, dbcs_converter, "host DBCS", NULL, NULL);
343
 
}
344
 
 
345
 
/*
346
 
 * Translate a DBCS EBCDIC character to a local multi-byte character.
347
 
 * Returns -1 for error, or the mb length.  NULL terminates.
348
 
 */
349
 
int
350
 
dbcs_to_mb(unsigned char ebc1, unsigned char ebc2, char *mb)
351
 
{
352
 
        UErrorCode err = U_ZERO_ERROR;
353
 
        unsigned char w[2];
354
 
        UChar Ubuf;
355
 
        int len;
356
 
 
357
 
        if (local_converter == NULL) {
358
 
                *mb = '?';
359
 
                *(mb + 1) = '\0';
360
 
                return 1;
361
 
        }
362
 
 
363
 
        /* Translate to Unicode first. */
364
 
        dbcs_to_unicode16(ebc1, ebc2, w);
365
 
        Ubuf = (w[0] << 8) | w[1];
366
 
 
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);
372
 
                return -1;
373
 
        }
374
 
        return len;
375
 
}
376
 
 
377
 
/*
378
 
 * Translate an SBCS EBCDIC character to a local multi-byte character.
379
 
 * Returns -1 for error, or the mb length.  NULL terminates.
380
 
 */
381
 
int
382
 
sbcs_to_mb(unsigned char ebc, char *mb)
383
 
{
384
 
        UErrorCode err = U_ZERO_ERROR;
385
 
        UChar Ubuf;
386
 
        int len;
387
 
 
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. */
392
 
                        *mb = ebc2asc[ebc];
393
 
                        *(mb + 1) = '\0';
394
 
                        return 1;
395
 
                }
396
 
 
397
 
                /* Have a local converter; use it below. */
398
 
                Ubuf = ebc2asc[ebc];
399
 
        } else {
400
 
                /* Have an SBCS converter.  Convert from SBCS to Unicode. */
401
 
                err = U_ZERO_ERROR;
402
 
                len = ucnv_toUChars(sbcs_converter, &Ubuf, 1, (char *)&ebc, 1,
403
 
                                &err);
404
 
                if (err != U_ZERO_ERROR &&
405
 
                                err != U_STRING_NOT_TERMINATED_WARNING) {
406
 
                        trace_ds("[toUChars failed, ICU error %d]\n",
407
 
                            (int)err);
408
 
                        return -1;
409
 
                }
410
 
        }
411
 
 
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);
417
 
                return -1;
418
 
        }
419
 
        return len;
420
 
}
421
 
 
422
 
/*
423
 
 * Translate a local multi-byte string to Unicode characters.
424
 
 * Returns -1 for error, or the length.  NULL terminates.
425
 
 */
426
 
int
427
 
mb_to_unicode(char *mb, int mblen, UChar *u, int ulen, UErrorCode *err)
428
 
{
429
 
        UErrorCode local_err;
430
 
        int len;
431
 
        Boolean print_errs = False;
432
 
 
433
 
        if (local_converter == NULL) {
434
 
                int i;
435
 
 
436
 
                for (i = 0; i < mblen; i++) {
437
 
                        u[i] = mb[i] & 0xff;
438
 
                }
439
 
                return mblen;
440
 
        }
441
 
        if (err == NULL) {
442
 
                err = &local_err;
443
 
                print_errs = True;
444
 
        }
445
 
        *err = U_ZERO_ERROR;
446
 
        len = ucnv_toUChars(local_converter, u, ulen, mb, mblen, err);
447
 
        if (*err != U_ZERO_ERROR && *err != U_STRING_NOT_TERMINATED_WARNING) {
448
 
                if (print_errs)
449
 
                        trace_ds("[toUChars failed, ICU error %d]\n",
450
 
                            (int)*err);
451
 
                return -1;
452
 
        }
453
 
        return len;
454
 
}
455
 
 
456
 
/*
457
 
 * Try to map a Unicode character to the Host SBCS character set.
458
 
 * Returns ASCII in cp[0].
459
 
 */
460
 
int
461
 
dbcs_map8(UChar u, unsigned char *cp)
462
 
{
463
 
        UErrorCode err = U_ZERO_ERROR;
464
 
        int len;
465
 
 
466
 
        if (!(u & ~0xff)) {
467
 
                *cp = u;
468
 
                return 1;
469
 
        }
470
 
        if (sbcs_converter != NULL) {
471
 
                len = ucnv_fromUChars(sbcs_converter, (char *)cp, 1, &u, 1,
472
 
                    &err);
473
 
                if ((err != U_ZERO_ERROR &&
474
 
                     err != U_STRING_NOT_TERMINATED_WARNING) ||
475
 
                    (*cp == '?' && u != '?')) {
476
 
                        *cp = ebc2asc[*cp];
477
 
                        return 0;
478
 
                } else
479
 
                        return 1;
480
 
        }
481
 
        return 0;
482
 
}
483
 
 
484
 
/*
485
 
 * Try to map a Unicode character to the Host DBCS character set.
486
 
 * Returns EBCDIC in cp[].
487
 
 */
488
 
int
489
 
dbcs_map16(UChar u, unsigned char *cp)
490
 
{
491
 
        UErrorCode err = U_ZERO_ERROR;
492
 
        int len;
493
 
 
494
 
        if (same_converter) {
495
 
                char tmp_cp[5];
496
 
 
497
 
                len = ucnv_fromUChars(dbcs_converter, tmp_cp, 5, &u, 1, &err);
498
 
                if (err != U_ZERO_ERROR ||
499
 
                    len < 3 ||
500
 
                    tmp_cp[0] != EBC_so)
501
 
                        return 0;
502
 
                cp[0] = tmp_cp[1];
503
 
                cp[1] = tmp_cp[2];
504
 
                return 1;
505
 
        } else {
506
 
                len = ucnv_fromUChars(dbcs_converter, (char *)cp, 2, &u, 1,
507
 
                                &err);
508
 
                return (err == U_ZERO_ERROR ||
509
 
                        err == U_STRING_NOT_TERMINATED_WARNING);
510
 
        }
511
 
}