« 关于词典软件 | 返回首页 | 一个 C 接口设计的问题 »

让 Erlang 的控制台支持中文

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 了一些东西,有兴趣的同学可以看看,其中也有一些字符转换的工作。

类似的地方就不多说了,稍微浏览过 Erlang 底层的一些 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 的内码也行。

留到以后再改吧。

Comments

现在应该没啥人用erlang了吧
io:format("~ts~n",[>]).
在utf8格式的erl文件顶部添加一行注释:%% coding: latin-1
找到同类了,支持一下
hi, is there any useful tool for clearing the terminal screen of erlang shell
操作系统中的故障恢复控制台意义非凡    进入21世纪也就进入了科技时代,计算机的广泛应用是进入信息时代的主要标志,计算机离不开操作系统,普通计算机离开了操作系统根本没法工作,在Windows2000/XP/2003操作系统中,有一棵系统故障的救命稻草,那就是故障恢复控制台。使用故障恢复控制台,我们不但可以进行包括启用和禁用服务,格式化驱动器,在本地驱动器上读写数据(包括被格式化为NTFS文件系统的驱动器)等操作,还利用故障恢复控制台执行许多其它管理任务。特别对于那些想通过从软盘或光盘上复制文件到硬盘上来修复系统,或者要对阻止计算机正常启动的服务进行重新配置的“高手”们,故障恢复控制台堪称利器。    进入故障恢复控制台,有两种方法:一种是直接利用系统安装光盘从光盘启动系统进入;另一种就是将故障恢复控制台安装到硬盘上,它会自动在系统启动菜单中增加一个选项,我们可以从中选择进入,我们可以通过这种方式来对我们的操作系统进行修复,使我们的信息不至于因为系统出了问题而丢失信息。 来源:控制台服务网www.bjddty.com.cn
erlang R13A还不准备解决这个问题 也许他们觉得他们那样做是对的,因为不可打印的字符太多!
呵呵好的~
erlang是干什么用的?我懒得百度.云风能否用简短的话概括?和游戏有什么很密切的关系?我知道LUA.
希望大家能一起学习Erlang
说道系统,我比较极端,总只在同一时间使用一种系统。
新年好!!!
持续关注云风,happy 牛 year!
我桌面有两台机器,都是双系统。所以 freebsd ubuntu windows 都用。 就昨天而言,我用的 less 阅读代码。配合 grep 查找,vi (非 vim) 修改。
云风读的英文版?
云风到底是在用 freebsd 还是 ubuntu 还是 windows?
云风是用什么工具来辅助阅读源码的? VIM吗?
erlang team 正在向 erlang 增加 unicode 支持。云风同学可以等待下一个(也许是下N个)版本,也可以尝试向 erlang-patchs 提交你的补丁。:D
LZ新年好。

Post a comment

非这个主题相关的留言请到:留言本