2
* Modifications Copyright 1993, 1994, 1995, 1996, 1999, 2000, 2001, 2002,
3
* 2003, 2004, 2005, 2006, 2007 by Paul Mattes.
4
* Original X11 Port Copyright 1990 by Jeff Sparkes.
5
* Permission to use, copy, modify, and distribute this software and its
6
* documentation for any purpose and without fee is hereby granted,
7
* provided that the above copyright notice appear in all copies and that
8
* both that copyright notice and this permission notice appear in
9
* supporting documentation.
11
* Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA 30332.
12
* All Rights Reserved. GTRC hereby grants public use of this software.
13
* Derivative works based on this software must incorporate this copyright
16
* x3270, c3270, s3270 and tcl3270 are distributed in the hope that they will
17
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file LICENSE
2
* Copyright (c) 1993-2009, Paul Mattes.
3
* Copyright (c) 1990, Jeff Sparkes.
4
* Copyright (c) 1989, Georgia Tech Research Corporation (GTRC), Atlanta, GA
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions are met:
10
* * Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* * Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* * Neither the names of Paul Mattes, Jeff Sparkes, GTRC nor the names of
16
* their contributors may be used to endorse or promote products derived
17
* from this software without specific prior written permission.
19
* THIS SOFTWARE IS PROVIDED BY PAUL MATTES, JEFF SPARKES AND GTRC "AS IS" AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL PAUL MATTES, JEFF SPARKES OR GTRC BE
23
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
* POSSIBILITY OF SUCH DAMAGE.
61
75
unsigned long cgcsgid = DEFAULT_CGEN | DEFAULT_CSET;
62
76
unsigned long cgcsgid_dbcs = 0L;
63
77
char *default_display_charset = "3270cg-1a,3270cg-1,iso8859-1";
64
char *converter_names;
66
#if defined(X3270_DISPLAY) /*[*/
67
unsigned char xk_selector = 0;
69
unsigned char auto_keymap = 0;
72
static enum cs_result resource_charset(char *csname, char *cs, char *ftcs);
73
typedef enum { CS_ONLY, FT_ONLY, BOTH } remap_scope;
74
static enum cs_result remap_chars(char *csname, char *spec, remap_scope scope,
76
static void remap_one(unsigned char ebc, KeySym iso, remap_scope scope,
78
#if defined(DEBUG_CHARSET) /*[*/
79
static enum cs_result check_charset(void);
80
static char *char_if_ascii7(unsigned long l);
82
static void set_cgcsgids(char *spec);
80
static enum cs_result charset_init2(char *csname, const char *codepage,
81
const char *cgcsgid, const char *display_charsets);
82
static void set_cgcsgids(const char *spec);
83
83
static int set_cgcsgid(char *spec, unsigned long *idp);
84
static void set_host_codepage(char *codepage);
84
85
static void set_charset_name(char *csname);
87
static char *host_codepage = CN;
86
88
static char *charset_name = CN;
89
charset_defaults(void)
91
/* Go to defaults first. */
92
(void) memcpy((char *)ebc2cg, (char *)ebc2cg0, 256);
93
(void) memcpy((char *)cg2ebc, (char *)cg2ebc0, 256);
94
(void) memcpy((char *)ebc2asc, (char *)ebc2asc0, 256);
95
(void) memcpy((char *)asc2ebc, (char *)asc2ebc0, 256);
96
#if defined(X3270_FT) /*[*/
97
(void) memcpy((char *)ft2asc, (char *)ft2asc0, 256);
98
(void) memcpy((char *)asc2ft, (char *)asc2ft0, 256);
103
static unsigned char save_ebc2cg[256];
104
static unsigned char save_cg2ebc[256];
105
static unsigned char save_ebc2asc[256];
106
static unsigned char save_asc2ebc[256];
107
#if defined(X3270_FT) /*[*/
108
static unsigned char save_ft2asc[256];
109
static unsigned char save_asc2ft[256];
115
(void) memcpy((char *)save_ebc2cg, (char *)ebc2cg, 256);
116
(void) memcpy((char *)save_cg2ebc, (char *)cg2ebc, 256);
117
(void) memcpy((char *)save_ebc2asc, (char *)ebc2asc, 256);
118
(void) memcpy((char *)save_asc2ebc, (char *)asc2ebc, 256);
119
#if defined(X3270_FT) /*[*/
120
(void) memcpy((char *)save_ft2asc, (char *)ft2asc, 256);
121
(void) memcpy((char *)save_asc2ft, (char *)asc2ft, 256);
126
restore_charset(void)
128
(void) memcpy((char *)ebc2cg, (char *)save_ebc2cg, 256);
129
(void) memcpy((char *)cg2ebc, (char *)save_cg2ebc, 256);
130
(void) memcpy((char *)ebc2asc, (char *)save_ebc2asc, 256);
131
(void) memcpy((char *)asc2ebc, (char *)save_asc2ebc, 256);
132
#if defined(X3270_FT) /*[*/
133
(void) memcpy((char *)ft2asc, (char *)save_ft2asc, 256);
134
(void) memcpy((char *)asc2ft, (char *)save_asc2ft, 256);
138
/* Get a character set definition. */
140
get_charset_def(const char *csname)
142
return get_fresource("%s.%s", ResCharset, csname);
145
#if defined(X3270_DBCS) /*[*/
147
* Initialize the DBCS conversion functions, based on resource values.
150
wide_resource_init(char *csname)
154
cn = get_fresource("%s.%s", ResDbcsConverters, csname);
158
en = get_fresource("%s.%s", ResLocalEncoding, csname);
160
en = appres.local_encoding;
161
Replace(converter_names, cn);
162
Replace(encoding, en);
164
return wide_init(cn, en);
170
91
* Change character sets.
173
94
charset_init(char *csname)
178
#if defined(X3270_DISPLAY) /*[*/
182
97
#if !defined(_WIN32) /*[*/
183
98
char *codeset_name;
100
const char *codepage;
102
const char *display_charsets;
103
#if defined(X3270_DBCS) /*[*/
104
const char *dbcs_cgcsgid = NULL;
105
const char *dbcs_display_charsets = NULL;
106
Boolean need_free = False;
186
109
#if !defined(_WIN32) /*[*/
187
110
/* Get all of the locale stuff right. */
190
113
/* Figure out the locale code set (character set encoding). */
191
114
codeset_name = nl_langinfo(CODESET);
115
#if defined(__CYGWIN__) /*[*/
117
* Cygwin's locale support is quite limited. If the locale
118
* indicates "US-ASCII", which appears to be the only supported
119
* encoding, ignore it and use the Windows ANSI code page, which
120
* observation indicates is what is actually supported.
122
* Hopefully at some point Cygwin will start returning something
123
* meaningful here and this logic will stop triggering.
125
if (!strcmp(codeset_name, "US-ASCII"))
126
codeset_name = xs_buffer("CP%d", GetACP());
192
128
set_codeset(codeset_name);
195
131
/* Do nothing, successfully. */
196
132
if (csname == CN || !strcasecmp(csname, "us")) {
198
133
set_cgcsgids(CN);
134
set_host_codepage(CN);
199
135
set_charset_name(CN);
200
#if defined(X3270_DISPLAY) || (defined(C3270) && !defined(_WIN32)) /*[*/
136
#if defined(X3270_DISPLAY) /*[*/
201
137
(void) screen_new_display_charsets(default_display_charset,
204
#if defined(_WIN32) /*[*/
205
set_display_charset("iso8859-1");
207
utf8_set_display_charsets(default_display_charset, "us");
140
(void) set_uni(CN, &codepage, &cgcsgid, &display_charsets);
141
#if defined(X3270_DBCS) /*[*/
142
(void) set_uni_dbcs("", NULL, NULL);
213
/* Figure out if it's already in a resource or in a file. */
214
cs = get_charset_def(csname);
216
strlen(csname) > ES_SIZE &&
217
!strcasecmp(csname + strlen(csname) - ES_SIZE, EURO_SUFFIX)) {
220
/* Grab the non-Euro definition. */
221
basename = xs_buffer("%.*s", (int)(strlen(csname) - ES_SIZE),
223
cs = get_charset_def(basename);
229
/* Grab the File Transfer character set. */
230
ftcs = get_fresource("%s.%s", ResFtCharset, csname);
234
cftcs = (ftcs == NULL)? NULL: NewString(ftcs);
236
/* Save the current definitions, and start over with the defaults. */
240
/* Check for auto-keymap. */
241
ak = get_fresource("%s.%s", ResAutoKeymap, csname);
243
auto_keymap = !strcasecmp(ak, "true");
247
/* Interpret them. */
248
rc = resource_charset(csname, ccs, cftcs);
254
#if defined(DEBUG_CHARSET) /*[*/
256
rc = check_charset();
261
#if defined(X3270_DBCS) /*[*/
262
else if (wide_resource_init(csname) < 0) {
268
#if defined(X3270_DISPLAY) /*[*/
269
/* Check for an XK selector. */
270
xks = get_fresource("%s.%s", ResXkSelector, csname);
272
xk_selector = (unsigned char) strtoul(xks, NULL, 0);
147
if (set_uni(csname, &codepage, &cgcsgid, &display_charsets) < 0)
149
if (appres.sbcs_cgcsgid != CN)
150
cgcsgid = appres.sbcs_cgcsgid; /* override */
151
#if defined(X3270_DBCS) /*[*/
152
if (set_uni_dbcs(csname, &dbcs_cgcsgid, &dbcs_display_charsets) == 0) {
153
if (appres.dbcs_cgcsgid != CN)
154
dbcs_cgcsgid = appres.dbcs_cgcsgid; /* override */
155
cgcsgid = xs_buffer("%s+%s", cgcsgid, dbcs_cgcsgid);
156
display_charsets = xs_buffer("%s+%s", display_charsets,
157
dbcs_display_charsets);
162
rc = charset_init2(csname, codepage, cgcsgid, display_charsets);
163
#if defined(X3270_DBCS) /*[*/
165
Free((char *)cgcsgid);
166
Free((char *)display_charsets);
280
176
/* Set a CGCSGID. Return 0 for success, -1 for failure. */
365
/* Define a charset from resources. */
280
/* Character set init, part 2. */
366
281
static enum cs_result
367
resource_charset(char *csname, char *cs, char *ftcs)
282
charset_init2(char *csname, const char *codepage, const char *cgcsgid,
283
const char *display_charsets)
285
const char *rcs = display_charsets;
373
#if defined(_WIN32) /*[*/
377
/* Interpret the spec. */
378
rc = remap_chars(csname, cs, (ftcs == NULL)? BOTH: CS_ONLY, &ne);
382
rc = remap_chars(csname, ftcs, FT_ONLY, &ne);
387
rcs = get_fresource("%s.%s", ResDisplayCharset, csname);
287
char *rcs_copy, *buf, *token;
389
289
/* Isolate the pieces. */
391
char *rcs_copy, *buf, *token;
393
buf = rcs_copy = NewString(rcs);
394
while ((token = strtok(buf, "+")) != CN) {
290
buf = rcs_copy = NewString(rcs);
291
while ((token = strtok(buf, "+")) != CN) {
398
295
#if defined(X3270_DBCS) /*[*/
403
popup_an_error("Extra %s value(s), ignoring",
300
popup_an_error("Extra charset value(s), ignoring");
411
307
#if defined(X3270_DBCS) /*[*/
412
308
/* Can't swap DBCS modes while connected. */
457
* Map a keysym name or literal string into a character.
458
* Returns NoSymbol if there is a problem.
461
parse_keysym(char *s, Boolean extended)
465
k = StringToKeysym(s);
469
else if (s[0] == '0' && s[1] == 'x') {
473
l = strtoul(s, &ptr, 16);
474
if (*ptr != '\0' || (l & ~0xffff))
480
if (k < ' ' || (!extended && k > 0xff))
486
/* Process a single character definition. */
488
remap_one(unsigned char ebc, KeySym iso, remap_scope scope, Boolean one_way)
492
/* Ignore mappings of EBCDIC control codes and the space character. */
496
/* If they want to map to a NULL or a blank, make it a one-way blank. */
502
if (!auto_keymap || iso <= 0xff) {
503
#if defined(X3270_FT) /*[*/
507
if (scope == BOTH || scope == CS_ONLY) {
511
if (cg2asc[cg] == iso || iso == 0) {
518
ebc2cg[ebc] = CG_boxsolid;
527
#if defined(X3270_FT) /*[*/
528
if (iso <= 0xff && ebc > 0x40) {
529
/* Change the file transfer translation table. */
532
* We have an alternate mapping of an EBCDIC
533
* code to an ASCII code. Modify the existing
534
* ASCII(ft)-to-ASCII(desired) maps.
536
* This is done by figuring out which ASCII
537
* code the host usually translates the given
538
* EBCDIC code to (asc2ft0[ebc2asc0[ebc]]).
539
* Now we want to translate that code to the
540
* given ISO code, and vice-versa.
542
aa = asc2ft0[ebc2asc0[ebc]];
547
} else if (scope == FT_ONLY) {
549
* We have a map of how the host translates
550
* the given EBCDIC code to an ASCII code.
551
* Generate the translation between that code
552
* and the ISO code that we would normally
553
* use to display that EBCDIC code.
555
ft2asc[iso] = ebc2asc[ebc];
556
asc2ft[ebc2asc[ebc]] = iso;
562
add_xk(iso, (KeySym)ebc2asc[ebc]);
567
* Parse an EBCDIC character set map, a series of pairs of numeric EBCDIC codes
570
* If the keysym is in the range 1..255, it is a remapping of the EBCDIC code
571
* for a standard Latin-1 graphic, and the CG-to-EBCDIC map will be modified
574
* Otherwise (keysym > 255), it is a definition for the EBCDIC code to use for
575
* a multibyte keysym. This is intended for 8-bit fonts that with special
576
* characters that replace certain standard Latin-1 graphics. The keysym
577
* will be entered into the extended keysym translation table.
579
static enum cs_result
580
remap_chars(char *csname, char *spec, remap_scope scope, int *ne)
587
enum cs_result rc = CS_OKAY;
588
Boolean is_table = False;
589
Boolean one_way = False;
591
/* Pick apart a copy of the spec. */
592
s = spec = NewString(spec);
593
while (isspace(*s)) {
596
if (!strncmp(s, "#table", 6)) {
606
while ((tok = strtok(s, " \t\n")) != CN) {
608
popup_an_error("Charset has more than 256 "
618
iso = strtoul(tok, &ptr, 0);
619
if (ptr == tok || *ptr != '\0' || iso > 256L) {
620
if (strlen(tok) == 1)
623
popup_an_error("Invalid charset "
630
remap_one(ebc, iso, scope, one_way);
636
popup_an_error("Charset has %d entries, need 256", ebc);
640
* The entire EBCDIC-to-ASCII mapping has been defined.
641
* Make sure that any printable ASCII character that
642
* doesn't now map back onto itself is mapped onto an
647
for (i = 0; i < 256; i++) {
648
if ((i & 0x7f) > 0x20 && i != 0x7f &&
650
ebc2asc[asc2ebc[i]] != i) {
656
while ((ns = split_dresource(&s, &ebcs, &isos))) {
660
if (ebcs[0] == '*') {
666
((ebc = strtoul(ebcs, &ptr, 0)),
667
ptr == ebcs || *ptr != '\0') ||
668
(iso = parse_keysym(isos, True)) == NoSymbol) {
669
popup_an_error("Cannot parse %s \"%s\", entry %d",
670
ResCharset, csname, *ne);
674
remap_one(ebc, iso, scope, one_way);
681
#if defined(DEBUG_CHARSET) /*[*/
683
char_if_ascii7(unsigned long l)
687
if (((l & 0x7f) > ' ' && (l & 0x7f) < 0x7f) || l == 0xff) {
688
(void) sprintf(buf, " ('%c')", (char)l);
696
#if defined(DEBUG_CHARSET) /*[*/
698
* Verify that a character set is not ambiguous.
699
* (All this checks is that multiple EBCDIC codes map onto the same ISO code.
700
* Hmm. God, I find the CG stuff confusing.)
702
static enum cs_result
707
enum cs_result rc = CS_OKAY;
709
for (iso = 1; iso <= 255; iso++) {
710
unsigned char multi[256];
716
for (ebc = 0x41; ebc < 0xff; ebc++) {
717
if (cg2asc[ebc2cg[ebc]] == iso) {
718
multi[n_multi] = ebc;
723
xs_warning("Display character 0x%02x%s has multiple "
724
"EBCDIC definitions: X'%02X', X'%02X'%s",
725
iso, char_if_ascii7(iso),
726
multi[0], multi[1], (n_multi > 2)? ", ...": "");
342
/* Return the current host codepage. */
344
get_host_codepage(void)
346
return (host_codepage != CN)? host_codepage: "037";
734
349
/* Return the current character set name. */