原创作者: 云风   阅读:2215次   评论:0条   更新时间:2011-05-26    
感谢云风,允许我转帖他的这篇Blog。原文地址是:
http://blog.codingnow.com/2008/12/erlang_shell_utf-8.html

 Amazon 的书送的真快,原来以为周三才能到的,结果昨天就到了。表扬一下。

 

拿到《Erlang 程序设计》,花了一晚上读了 1/3 。今天实作了一下。

 

发现在 Ubuntu 下用 apt 装的 Erlang (5.6.5) 的 Shell 不支持中文,这让我郁闷了一把。:(

 

好在 Erlang 是开源的,有源码在手,有何畏惧。晚上,我卯足了劲研究 Erlang 的 source code ,想找到不支持中文显示的原因。

 

表现是这样的,我的环境是 UTF-8 的,当我输入汉字时,在 Erlang Shell 里立刻被转义为了 \xxx 这样的 8 进制数。在《Erlang 程序设计》的 2.11 / 21 页写道,“这实际上是显示终端的字符集和区域设定有问题”。我改了半天,都没有把汉字鼓捣出来,感觉不是我的设置问题。

 

但是,在同事的 Windows 机器上的 Erlang Shell 下却是可以正确显示中文的。

 

我想,读读源码也好,正好可以实际体会一下 Erlang 的代码风格。


 

在读代码的过程中绕了不少弯路,找到许多貌似会影响输出的地方,改过后都没有效果。

 

比如在 erts/emulator/beam/erl_printf_term.c 里有一个 IS_CNTRL 的宏,为 LATIN1 的字符集 hard code 了一些东西,有兴趣的同学可以看看,其中也有一些字符转换的工作。

 

类似的地方就不多说了,稍微浏览过 Erland 底层的一些 C 代码后,感觉质量还不错,不过在可移植性和 C 语言标准上,没有 Lua 的源代码严谨 :) 。因为 Lua 里就没有为某些字符集特别定制的代码。好吧,我就看了几个小时而已,权当是一个偏见。

 

最终找到了关键的地方,一共有两处:

 

一处在 lib/stdlib/src/io_lib.erl 文件里,打开这个文件就可以看到前面有些关于 ISO 8859-1 / Latin-1 的信息。搜索这个文件,会发现它把 $\240 到 $\377 之间的字符任何事实可以打印的。但是对于 UTF-8 编码来说,这不够。把 $\240 改成 $\200 即可。

 

在 Erlang Shell 里,只有整个整数数组里的数字都是可答应字符,才会显示成 "xxxxx" 的形式,否则就是 [xxx,xxx,xxx,xxx] 这样的。做了这个修改后,就不会在有 UTF-8 的中文串被转换为 [数字] 了。

 

第二处在 C 代码里。

 

因为 Erlang 的内部是自己管理的若干进程(非操作系统进程),为了让用户输入和输出可以统一,所以实际上,和用户交互的 IO 是序列化在一个进程里完成的。所以我们看到的 io:format 的输出,其实是向管理 IO 的进程发了一个消息而已。

 

为了找到这个最终真正处理输入输出的进程,我查看了 Erlang 的源代码,就是 lib/kernel/src 的部分。最后发现,是 user 模块最最终的汇总,然后交给 user_drv 去处理 IO 。

 

但是,我们知道 Erlang 自己是不可能完成 IO 操作的,必然会涉及 C 实现的代码,去跟 OS 交互。在 user_drv 里我们发现了一个叫 tty_sl 的东西。这就是 C 实现的终端部分了。

 

Erlang 和其它语言交互的方式很有趣,是用进程间(不一定是操作系统级的)通讯完成的,用二进制数据流交互。这跟我们游戏服务器的过进程结构很像。不得不说,Erlang 做的非常优美。今天太晚,不展开评论了。

 

回到主话题上,这个 tty_sl 的实现在 /erts/emulator/drivers/unix/ttsl_drv.c 。读一读这个源文件,大概就能理解 C 模块如何跟 Erlang 交互的了。

 

关于中文显示的问题,正在于,这个实现中,hard code 写死了当字符大于等于 128 时的处理方法:转换为 \八进制表示。

 

我简单增加了一个 ISPRINT 宏,替换掉原来的 isprint 调用,让大于等于 128 的字符也返回 true 。重新编译安装后,Erlang 的 Shell 就可以在 Ubuntu 下正确显示中文了。

 

不过还有一个问题,光标的处理不太正确,比如退格键可以消掉半个汉字。我想,比较简单并健壮的修改方法应该是把这个 tty 服务的内码改成 UCS-2 的,这样比较容易让单个汉字变成原子的。当然,想办法让它正确处理 UTF-8 的内码也行。

 

留到以后再改吧。

评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

文章信息

Global site tag (gtag.js) - Google Analytics