aboutsummaryrefslogtreecommitdiff
path: root/shells
diff options
context:
space:
mode:
authorAkinori MUSHA <knu@FreeBSD.org>2002-05-11 21:48:26 +0000
committerAkinori MUSHA <knu@FreeBSD.org>2002-05-11 21:48:26 +0000
commitf1f99beceb03441db22a6a80c56f0514e333fe47 (patch)
treeb426bb2d7e89223183efd1ed2035f18c8358183c /shells
parent453902851adaf5e7d8b0ebe65eeb9b88ecf7b6c7 (diff)
downloadports-f1f99beceb03441db22a6a80c56f0514e333fe47.tar.gz
ports-f1f99beceb03441db22a6a80c56f0514e333fe47.zip
Add zsh+euc, Zsh with EUC encoding support.
This is just an experimental hack and cannot happily be merged into the upstream. Zsh's line editor apparently needs a rewrite in order to support multi-byte encodings because it strongly relies on the single-byte character scheme. These patches are mostly based on the work by ono@ono.org (Thanks!): http://www.ono.org/software/zsh-euc/ What I did over this is disable the hack for non-EUC locales. Maybe the patches can be moved to shells/zsh in the future, but it's premature for the moment. Notes: - forward-char, backward-char and backward-delete-char with no numeric argument should work properly with this hack. - Completion and redisplay should work fine. - There can be some trivial side-effects. - JIS X0201-Roman and JIS X0208-Kanji are supported. - JIS X0201-Katakana and JIS X0212 Kanji are NOT supported. - Only tested with the EUC-JP (ja_JP.eucJP) locale. I'm not sure if it works for GB 2312/CNS 11643-1/KS X 1001. Any feedbacks is welcome, especially a patch if it does not work. :)
Notes
Notes: svn path=/head/; revision=58933
Diffstat (limited to 'shells')
-rw-r--r--shells/Makefile1
-rw-r--r--shells/zsh+euc_hack/Makefile18
-rw-r--r--shells/zsh+euc_hack/files/patch-Src::Zle::compmatch.c57
-rw-r--r--shells/zsh+euc_hack/files/patch-Src::Zle::zle.c11
-rw-r--r--shells/zsh+euc_hack/files/patch-Src::Zle::zle_main.c199
-rw-r--r--shells/zsh+euc_hack/files/patch-Src::Zle::zle_move.c38
-rw-r--r--shells/zsh+euc_hack/files/patch-Src::Zle::zle_refresh.c47
-rw-r--r--shells/zsh+euc_hack/files/patch-Src::Zle::zle_utils.c20
-rw-r--r--shells/zsh+euc_hack/files/patch-config.h.in9
-rw-r--r--shells/zsh+euc_hack/pkg-comment1
10 files changed, 401 insertions, 0 deletions
diff --git a/shells/Makefile b/shells/Makefile
index e2d663fd4547..c147ebb71150 100644
--- a/shells/Makefile
+++ b/shells/Makefile
@@ -21,6 +21,7 @@
SUBDIR += vshnu
SUBDIR += wapsh
SUBDIR += zsh
+ SUBDIR += zsh+euc_hack
SUBDIR += zsh-devel
.include <bsd.port.subdir.mk>
diff --git a/shells/zsh+euc_hack/Makefile b/shells/zsh+euc_hack/Makefile
new file mode 100644
index 000000000000..1be9d36dde4a
--- /dev/null
+++ b/shells/zsh+euc_hack/Makefile
@@ -0,0 +1,18 @@
+# New ports collection makefile for: zsh with EUC encoding support
+# Date created: 12 May 2002
+# Whom: Akinori MUSHA aka knu <knu@idaemons.org>
+#
+# $FreeBSD$
+#
+
+MASTERDIR= ${.CURDIR}/../zsh
+
+PKGNAMESUFFIX= +euc_hack
+
+MAINTAINER= knu@FreeBSD.org
+
+EXTRA_PATCHES= ${.CURDIR}/files/patch-*
+
+COMMENT= ${.CURDIR}/pkg-comment
+
+.include "${MASTERDIR}/Makefile"
diff --git a/shells/zsh+euc_hack/files/patch-Src::Zle::compmatch.c b/shells/zsh+euc_hack/files/patch-Src::Zle::compmatch.c
new file mode 100644
index 000000000000..3b5fb085e82f
--- /dev/null
+++ b/shells/zsh+euc_hack/files/patch-Src::Zle::compmatch.c
@@ -0,0 +1,57 @@
+--- Src/Zle/compmatch.c.orig Tue Apr 3 20:25:13 2001
++++ Src/Zle/compmatch.c Thu May 9 07:59:05 2002
+@@ -1309,6 +1309,9 @@
+ while (la && lb) {
+ if (*sa != *sb) {
+ /* Different characters, try the matchers. */
++#ifdef ZSH_EUC
++ono:
++#endif
+ for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) {
+ mp = ms->matcher;
+ if (mp && !mp->flags && mp->wlen > 0 && mp->llen > 0 &&
+@@ -1354,6 +1357,13 @@
+ }
+ if (!t)
+ break;
++#ifdef ZSH_EUC
++ } else if (locale_is_euc &&
++ (_mbmap_euc[*(unsigned char*)sa] & _MB1) &&
++ (_mbmap_euc[*((unsigned char*)sa+1)] & _MB2) &&
++ *(sa+1) != *(sb+1)) {
++ goto ono;
++#endif
+ } else {
+ /* Same character, just take it. */
+ if (rr <= 1) {
+@@ -1580,6 +1590,30 @@
+ if (check_cmdata(md, sfx))
+ return ret;
+
++#ifdef ZSH_EUC
++ if (locale_is_euc) {
++ if (sfx)
++ for (l = 0, p = str, q = md->str;
++ l < len && l < md->len && p[ind] == q[ind];
++ l++, p += add, q += add);
++ else
++ for (l = 0, p = str, q = md->str;;) {
++ if (!(l < len && l < md->len))
++ break;
++
++ if ((_mbmap_euc[*(unsigned char*)p] & _MB1) && (_mbmap_euc[*((unsigned char*)p+1)] & _MB2)) {
++ if (*p == *q && *(p+1) == *(q+1)) {
++ l+=2, p+=2, q+=2;
++ } else
++ break;
++ } else {
++ if (*p != *q)
++ break;
++ l++, p++, q++;
++ }
++ }
++ } else
++#endif
+ for (l = 0, p = str, q = md->str;
+ l < len && l < md->len && p[ind] == q[ind];
+ l++, p += add, q += add);
diff --git a/shells/zsh+euc_hack/files/patch-Src::Zle::zle.c b/shells/zsh+euc_hack/files/patch-Src::Zle::zle.c
new file mode 100644
index 000000000000..f0e1e59e93ec
--- /dev/null
+++ b/shells/zsh+euc_hack/files/patch-Src::Zle::zle.c
@@ -0,0 +1,11 @@
+--- Src/Zle/zle.h.orig Tue May 23 17:20:57 2000
++++ Src/Zle/zle.h Thu May 9 06:49:30 2002
+@@ -194,3 +194,8 @@
+ /* Invalidate the completion list. */
+
+ #define invalidatelist() runhookdef(INVALIDATELISTHOOK, NULL)
++
++#ifdef ZSH_EUC
++#define _MB1 0x01
++#define _MB2 0x02
++#endif
diff --git a/shells/zsh+euc_hack/files/patch-Src::Zle::zle_main.c b/shells/zsh+euc_hack/files/patch-Src::Zle::zle_main.c
new file mode 100644
index 000000000000..2f4ca58d6109
--- /dev/null
+++ b/shells/zsh+euc_hack/files/patch-Src::Zle::zle_main.c
@@ -0,0 +1,199 @@
+--- Src/Zle/zle_main.c.orig Fri May 18 00:56:13 2001
++++ Src/Zle/zle_main.c Thu May 9 07:53:36 2002
+@@ -141,6 +141,163 @@
+ static int delayzsetterm;
+ #endif
+
++#ifdef ZSH_EUC
++/**/
++mod_export int locale_is_euc;
++
++# if defined(__uxps__) || defined(sgi) || defined(aix) || defined(__CYGWIN__) || defined(linux)
++char STRLANGEUCJP[] = { 'j', 'a', '_', 'J', 'P', '.', 'E', 'U', 'C', '\0' };
++char STRLANGEUCKR[] = { 'k', 'o', '_', 'K', 'R', '.', 'E', 'U', 'C', '\0' };
++# if defined(__uxps__)
++char STRLANGEUCJPB[] = { 'j', 'a', 'p', 'a', 'n', '\0' };
++char STRLANGEUCKRB[] = { 'k', 'o', 'r', 'e', 'a', '\0' };
++# elif defined(linux)
++char STRLANGEUCJPB[] = { 'j', 'a', '_', 'J', 'P', '.', 'u', 'j', 'i', 's',
++ '\0' };
++char STRLANGEUCKRB[] = { 'k', 'o', '_', 'K', 'R', '.', 'e', 'u', 'c', '\0' };
++# elif defined(aix)
++char STRLANGEUCJPB[] = { 'j', 'a', '_', 'J', 'P', '\0' };
++char STRLANGEUCKRB[] = { 'k', 'o', '_', 'K', 'R', '\0' };
++# else
++char STRLANGEUCJPB[] = { '\0' };
++char STRLANGEUCKRB[] = { '\0' };
++# endif
++char STRLANGSJIS[] = { 'j', 'a', '_', 'J', 'P', '.', 'S', 'J', 'I', 'S',
++ '\0' };
++char STRLANGSJISB[] = { '\0' };
++char STRLANGBIG5[] = { 'z', 'h', '_', 'T', 'W', '.', 'B', 'i', 'g', '5',
++ '\0' };
++char STRLANGEUCZH[] = { '\0' };
++char STRLANGEUCZHB[] = { '\0' };
++# elif defined(__FreeBSD__)
++char STRLANGEUCJP[] = { 'j', 'a', '_', 'J', 'P', '.', 'e', 'u', 'c', 'J',
++ 'P', '\0' };
++char STRLANGEUCJPB[] = { 'j', 'a', '_', 'J', 'P', '.', 'E', 'U', 'C', '\0' };
++char STRLANGEUCKR[] = { 'k', 'o', '_', 'K', 'R', '.', 'e', 'u', 'c', 'K',
++ 'R', '\0' };
++char STRLANGEUCKRB[] = { 'k', 'o', '_', 'K', 'R', '.', 'E', 'U', 'C', '\0' };
++char STRLANGEUCZH[] = { 'z', 'h', '_', 'C', 'N', '.', 'e', 'u', 'c', 'C',
++ 'N', '\0' };
++char STRLANGEUCZHB[] = { 'z', 'h', '_', 'C', 'N', '.', 'E', 'U', 'C', '\0' };
++char STRLANGSJIS[] = { 'j', 'a', '_', 'J', 'P', '.', 'S', 'J', 'I', 'S',
++ '\0' };
++char STRLANGSJISB[] = { 'j', 'a', '_', 'J', 'P', '.', 'S', 'h', 'i', 'f',
++ 't', '_', 'J', 'I', 'S', '\0' };
++char STRLANGBIG5[] = { 'z', 'h', '_', 'T', 'W', '.', 'B', 'i', 'g', '5',
++ '\0' };
++# elif defined(__uxpm__)
++char STRLANGEUCJP[] = { 'j', 'a', 'p', 'a', 'n', '\0' };
++char STRLANGEUCKR[] = { 'k', 'o', 'r', 'e', 'a', '\0' };
++char STRLANGEUCZH[] = { '\0' };
++char STRLANGEUCJPB[] = { '\0' };
++char STRLANGEUCKRB[] = { '\0' };
++char STRLANGEUCZHB[] = { '\0' };
++char STRLANGSJIS[] = { '\0' };
++char STRLANGSJISB[] = { '\0' };
++char STRLANGBIG5[] = { '\0' };
++# elif defined(SOLARIS2)
++char STRLANGEUCJP[] = { 'j', 'a', '\0' };
++char STRLANGEUCKR[] = { 'k', 'o', '\0' };
++char STRLANGEUCZH[] = { '\0' };
++char STRLANGEUCJPB[] = { 'j', 'a', 'p', 'a', 'n', 'e', 's', 'e', '\0' };
++char STRLANGEUCKRB[] = { 'k', 'o', 'r', 'e', 'a', 'n', '\0' };
++char STRLANGEUCZHB[] = { '\0' };
++char STRLANGSJIS[] = { '\0' };
++char STRLANGSJISB[] = { '\0' };
++char STRLANGBIG5[] = { '\0' };
++# elif defined(hpux)
++char STRLANGEUCJP[] = { 'j', 'a', '_', 'J', 'P', '.', 'e', 'u', 'c', 'J', 'P' };
++char STRLANGEUCKR[] = { 'k', 'o', '_', 'K', 'R', '.', 'e', 'u', 'c', 'K', 'R' };
++char STRLANGEUCZH[] = { '\0' };
++char STRLANGEUCJPB[] = { '\0' };
++char STRLANGEUCKRB[] = { '\0' };
++char STRLANGEUCZHB[] = { '\0' };
++char STRLANGSJIS[] = { '\0' };
++char STRLANGSJISB[] = { '\0' };
++char STRLANGBIG5[] = { '\0' };
++# else
++char STRLANGEUCJP[] = { '\0' };
++char STRLANGEUCKR[] = { '\0' };
++char STRLANGEUCZH[] = { '\0' };
++char STRLANGEUCJPB[] = { '\0' };
++char STRLANGEUCKRB[] = { '\0' };
++char STRLANGEUCZHB[] = { '\0' };
++char STRLANGSJIS[] = { '\0' };
++char STRLANGSJISB[] = { '\0' };
++char STRLANGBIG5[] = { '\0' };
++# endif
++
++/**/
++mod_export unsigned char _mbmap_euc[256] = {
++/* first byte 0x8e,0xa0 - 0xf4 */
++/* second byte 0xa0 - 0xfe */
++/* 0 - 7f all 0 */
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
++/* 80 81 82 83 */
++ 0, 0, 0, 0,
++/* 84 85 86 87 */
++ 0, 0, 0, 0,
++/* 88 89 8a 8b */
++ 0, 0, 0, 0,
++/* 8c 8d 8e 8f */
++ 0, 0, _MB1, 0,
++/* 90 - 9f all 0 */
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
++/* a0 a1 a2 a3 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* a4 a5 a6 a7 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* a8 a9 aa ab */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* ac ad ae af */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* b0 b1 b2 b3 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* b4 b5 b6 b7 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* b8 b9 ba bb */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* bc bd be bf */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* c0 c1 c2 c3 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* c4 c5 c6 c7 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* c8 c9 ca cb */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* cc cd ce cf */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* d0 d1 d2 d3 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* d4 d5 d6 d7 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* d8 d9 da db */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* dc dd de df */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* e0 e1 e2 e3 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* e4 e5 e6 e7 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* e8 e9 ea eb */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* ec ed ee ef */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* f0 f1 f2 f3 */
++ _MB1|_MB2, _MB1|_MB2, _MB1|_MB2, _MB1|_MB2,
++/* f4 f5 f6 f7 */
++ _MB1|_MB2, _MB2, _MB2, _MB2,
++/* f8 f9 fa fb */
++ _MB2, _MB2, _MB2, _MB2,
++/* fc fd fe ff */
++ _MB2, _MB2, _MB2, 0,
++};
++
++#endif
++
+ /* set up terminal */
+
+ /**/
+@@ -1117,6 +1274,32 @@
+ int
+ setup_(Module m)
+ {
++#ifdef ZSH_EUC
++ char *euc_locales[] = {
++ STRLANGEUCJP,
++ STRLANGEUCKR,
++ STRLANGEUCZH,
++ STRLANGEUCJPB,
++ STRLANGEUCKRB,
++ STRLANGEUCZHB,
++ NULL
++ };
++ char **p;
++ char *tcp;
++
++ locale_is_euc = 0;
++
++ if ((tcp = setlocale("LC_CTYPE", NULL)) != NULL ||
++ (tcp = getenv("LANG")) != NULL) {
++ for (p = euc_locales; *p != NULL; p++) {
++ if (strcmp(tcp, *p) == 0) {
++ locale_is_euc = 1;
++ break;
++ }
++ }
++ }
++#endif
++
+ /* Set up editor entry points */
+ trashzleptr = trashzle;
+ refreshptr = zrefresh;
diff --git a/shells/zsh+euc_hack/files/patch-Src::Zle::zle_move.c b/shells/zsh+euc_hack/files/patch-Src::Zle::zle_move.c
new file mode 100644
index 000000000000..b4215fbe64cc
--- /dev/null
+++ b/shells/zsh+euc_hack/files/patch-Src::Zle::zle_move.c
@@ -0,0 +1,38 @@
+--- Src/Zle/zle_move.c.orig Sat Jul 3 22:18:00 1999
++++ Src/Zle/zle_move.c Thu May 9 17:55:46 2002
+@@ -159,6 +159,17 @@
+ int
+ forwardchar(char **args)
+ {
++#ifdef ZSH_EUC
++ if (locale_is_euc) {
++ if (zmult == 1) {
++ if (_mbmap_euc[line[cs]] & _MB1 &&
++ cs+1 <= ll &&
++ _mbmap_euc[line[cs+1]] & _MB2) {
++ cs++;
++ }
++ }
++ }
++#endif
+ cs += zmult;
+ if (cs > ll)
+ cs = ll;
+@@ -171,6 +182,17 @@
+ int
+ backwardchar(char **args)
+ {
++#ifdef ZSH_EUC
++ if (locale_is_euc) {
++ if (zmult == 1) {
++ if (_mbmap_euc[line[cs-1]] & _MB2 &&
++ cs-2 >=0 &&
++ _mbmap_euc[line[cs-2]] & _MB1) {
++ cs--;
++ }
++ }
++ }
++#endif
+ cs -= zmult;
+ if (cs > ll)
+ cs = ll;
diff --git a/shells/zsh+euc_hack/files/patch-Src::Zle::zle_refresh.c b/shells/zsh+euc_hack/files/patch-Src::Zle::zle_refresh.c
new file mode 100644
index 000000000000..47d7aa6fa867
--- /dev/null
+++ b/shells/zsh+euc_hack/files/patch-Src::Zle::zle_refresh.c
@@ -0,0 +1,47 @@
+--- Src/Zle/zle_refresh.c.orig Mon Sep 10 19:48:51 2001
++++ Src/Zle/zle_refresh.c Thu May 9 08:36:47 2002
+@@ -647,7 +647,11 @@
+ static void
+ refreshline(int ln)
+ {
++#ifdef ZSH_EUC
++ unsigned char *nl, *ol, *p1; /* line buffer pointers */
++#else
+ char *nl, *ol, *p1; /* line buffer pointers */
++#endif
+ int ccs = 0, /* temporary count for cursor position */
+ char_ins = 0, /* number of characters inserted/deleted */
+ col_cleareol, /* clear to end-of-line from this column */
+@@ -753,7 +757,32 @@
+ for (;;) {
+ if (*nl && *ol && nl[1] == ol[1]) /* skip only if second chars match */
+ /* skip past all matching characters */
++#ifdef ZSH_EUC
++ {
++ if (locale_is_euc) {
++ for (; *nl && (*nl == *ol); nl++, ol++, ccs++) {
++ if (_mbmap_euc[*nl] & _MB1) {
++ if (*(ol+1) == '\0')
++ continue;
++ if (_mbmap_euc[*(nl+1)] & _MB2) {
++ if (*(nl+1) != *(ol+1))
++ break;
++ else {
++ nl++;
++ ol++;
++ ccs++;
++ }
++ } else if (*(nl+1) == '\0') {
++ continue;
++ }
++ }
++ }
++ } else
++#endif
+ for (; *nl && (*nl == *ol); nl++, ol++, ccs++) ;
++#ifdef ZSH_EUC
++ }
++#endif
+
+ if (!*nl) {
+ if (ccs == winw && hasam && char_ins > 0 && ins_last
diff --git a/shells/zsh+euc_hack/files/patch-Src::Zle::zle_utils.c b/shells/zsh+euc_hack/files/patch-Src::Zle::zle_utils.c
new file mode 100644
index 000000000000..6c61530ec524
--- /dev/null
+++ b/shells/zsh+euc_hack/files/patch-Src::Zle::zle_utils.c
@@ -0,0 +1,20 @@
+--- Src/Zle/zle_utils.c.orig Mon Mar 26 17:58:34 2001
++++ Src/Zle/zle_utils.c Thu May 9 17:57:20 2002
+@@ -197,6 +197,17 @@
+ mod_export void
+ backdel(int ct)
+ {
++#ifdef ZSH_EUC
++ if (locale_is_euc) {
++ if (ct == 1) {
++ if (_mbmap_euc[line[cs-1]] & _MB2 &&
++ cs-2 >=0 &&
++ _mbmap_euc[line[cs-2]] & _MB1) {
++ ct = 2;
++ }
++ }
++ }
++#endif
+ shiftchars(cs -= ct, ct);
+ }
+
diff --git a/shells/zsh+euc_hack/files/patch-config.h.in b/shells/zsh+euc_hack/files/patch-config.h.in
new file mode 100644
index 000000000000..50ebd1b2fe8a
--- /dev/null
+++ b/shells/zsh+euc_hack/files/patch-config.h.in
@@ -0,0 +1,9 @@
+--- config.h.in.orig Tue Oct 16 21:46:09 2001
++++ config.h.in Thu May 9 06:49:30 2002
+@@ -756,3 +756,6 @@
+
+ /* Define if you have the socket library (-lsocket). */
+ #undef HAVE_LIBSOCKET
++
++/* zsh euc completion */
++#define ZSH_EUC 1
diff --git a/shells/zsh+euc_hack/pkg-comment b/shells/zsh+euc_hack/pkg-comment
new file mode 100644
index 000000000000..b2897090b46b
--- /dev/null
+++ b/shells/zsh+euc_hack/pkg-comment
@@ -0,0 +1 @@
+The Z shell with EUC encoding support