52 FreeBSD连载:外挂式中文显示与输入软件

外挂式中文显示与输入软件对于支持中文的软件,可以使用自己的方式处理中文的显示与输入 。然而更一般的软件中,都没有直接提供中文支持,有些能够部分识别中文但无法处理中文输入,如Netscape Navigator 。有些根本不能识别中文,有些甚至将8位字符作为非法字符来看待 。对于最后一种过滤8位字符的情况,是没有办法能使其正常显示、输入中文,但对于前两种情况,就有变通的方式使其正常显示和输入汉字 。
动态连接库的wrap技术
X Window下的客户程序要显示字符,需要调用libX11.so.6动态连接库中的XDrawString()等函数进行具体处理显示,如果这个函数能够区分出中文字符,并自动使用合适的中文字体进行显示,那么客户程序就能正常显示中文 。因而最基本的想法是修改X11R6中这些相关的显示处理函数,使它们能正常显示中文 。当然这可以通过直接修改XFree86发行版本中这个函数的源代码,并通过重新编译、安装库函数来做到 。然而这需要更改原有的正式发行版本,不是每个用户都愿意并且能够重新编译X系统的,并且这种方法对于不具备源代码的商业X服务器系统就不使用 。而且更改libX11.so.6也不太安全,缺乏灵活性,因此最好不更改原有的连接库,就能达到正确处理中文的目的 。
由于一般的应用程序使用动态连接的方式,在应用程序载入内存时,系统才将具体的动态连接库连接上 。因此如果在系统载入标准的库之前,预先载入一个包含同样名字函数的动态连接库与应用程序连接,那么程序会使用先连接的第一个库中的同名函数库,而非原有的标准库函数,这种方式就称为包装(wrap)的方法 。
现代Unix都支持这种预连接动态连接库的能力,系统在载入动态连接库之前,首先查看LD_PRELOAD环境变量,如果这个变量定义了一个动态连接库,那么就在连接其他标准动态连接库之前先连接这个变量定义的动态连接库 。因此如果这个预载入的动态库中有XDrawString()等函数的定义,那么它们就覆盖了系统中libX11.so.6库中的原有定义,而这个包装库可以通过直接访问libX11.so.6库来找到原有的标准函数,以真正处理显示 。
出于系统安全的考虑,系统不允许SetUID或SetGID的程序载入LDPRELOAD变量设置的动态连接库,这主要是避免用户通过定义自己动态连接库,在setuid等系统调用之后取得root权限 。因此包装技术不适合具有SetUID或SetGID属性的二进制执行文件 。此外,静态连接的执行程序在程序内部查找显示函数,也不适合使用包装技术(可以使用ldd命令来查看执行程序的动态连接关系,来判断其连接类型),除了这两种情况之外的其他X应用程序,就能支持中文包装技术 。
在使用包装技术时,另一个重要的问题是FreeBSD系统中存在两种不同的执行文件格式,a.out和ELF格式,它们分别使用a.out和ELF格式的动态连接库 。因此对于不同格式的执行文件,必须使用相应格式的包装库来包装不同的libX11.so动态连接库,不同格式的库不能相互连接 。3.0版本以上,缺省格式为ELF,缺省库也为ELF格式的动态连接库 。因此3.0版本以后要支持对a.out格式进行包装,一方面包装的动态连接库的位置就改变为/usr/X11R6/lib/aout/libX11.so.6.1,同时也需要使用编译器的-aout选项生成a.out格式的动态连接库,以进行包装 。当前发行的标准Packages均已经转向ELF,仍使用a.out格式主要是一些商业软件,如Netscape Navigator 。
Xcin AnyWhere
XA(Xcin AnyWhere)是一个较早的使用包装技术的中文输入软件,它原来仅仅是用于中文输入,为Xcin提供一个标准接口,后来被加入了中文显示能力 。具备中文显示能力的XA被称为XA CV版本 。

推荐阅读