基于Linux系统核心的汉字显示尝试( 三 )


这样一来,我们就又进了一步,得到了一个相对更好的版本 。但仍有问题没有解决 。敲入turbonetcfg,会发现菜单的边框字符也被当成汉字显示 。这是因为,这种边框字符是扩展字符,也使用了字符的第8位,因而被当作汉字来显示 。例如,单线一的制表符内码为0xC4,当连成一条长线就是由一连串0xC4组成,而0xC4C4正是汉字哪 。于是水平的制表符被一连串的哪字替代了 。要解决这个问题就非常不容易了,因为制表符的种类比较多,而且垂直制表符与其后面字符的组合型式又多种多样,因而很难判断出相应位置的字符是不是制表符,从理论上说,无论采取什么样的排除算法,都必然存在误判的情况,因为总存在二义性,没有充足的条件来推断出当前字符究竟是制表符还是汉字 。
我们一方面寻找更好的排除组合算法,一方面试图寻找其它的解决方案 。要想从根本上解决定个问题,必须利用其它的辅助信息,仅仅从缓冲区的字符来判断是不够的 。
经过一番努力,我们发现,在UNIX中使用扩展字符时,都要先输出字符转义序列(Escape sequence)来切换当前字符集 。字符转义序列是以控制字符Esc为首的控制命令,在UNIX的虚拟终端中完成终端控制命令,这种命令包括,移动光标座标、卷屏、删除、切换字符集等等 。也就是说在输出代表制表符的字符串之前,通常是要先输出特定的字符转义序列 。在console.c里,有根据字符转义序列命令来记录字符状态的变量 。结合该变量提供的信息,就可以非常干净地把制表符与汉字区别开来 。
在如上思路的指引下,我们又产生了新的解决方案 。经过改动得到了另一各版本 。在这个新版本上,turbonetcfg在初次绘制的时候,制表符与汉字被清晰地区分开来,结果是非常正确的 。但还有新的问题存在∶turbonetcfg在重绘的时候(如切换虚拟终端或是移动鼠标光标的时候),制表符还是变成了汉字,因为重绘完全依赖于缓冲区,而这时用来记录字符集状态的变量并不反映当前字符集状态 。问题还是没有最终解决 。我们又回到了起点 。∶( 看来问题的最终解决手段必须是把字符集的状态伴随每一个字符存在缓冲区中 。让我们来研究一下缓冲区的结构 。
每一个字符占用16bit的缓冲区,低8位是ASCII值,完全被利用,高8位包含前景颜色和背景颜色的属性,也没有多余的空间可以利用 。因而只能另外开辟新的缓冲区 。为了保持一致性,我们决定在原来的缓冲区后面添加相同大小的缓冲区,用来存放是否是汉字的信息 。
也许有读者会问,我们只需要为每个字符添加一bit的信息来标志是否是汉字就足够了,为什么还要开辟与原缓冲区大小相同的双倍缓冲区,是不是太浪费呢?
我们先放下这个问题,稍后再作回答 。其实,如果再添加一bit来标志是当前字符是汉字的左半边还是右半边的话,就会省去扫描屏幕上当前整行字符串的工作,这样一来,编程会更简单 。但是有读者会问,即使是这样,使用8bit总够用了吧?为什么还要使用16bit呢?
我们的作法是∶用低8位来存放汉字另外一半的内码,用高8位中的2 bit来存放上面所讲的辅助信息,高8位的剩余6位可以用来存放汉字或其它编码方式(如BIG5或日文、韩文)的信息,从而使我们可以实现同屏显示多种双字节语言的字符而不会有相互干扰 。另外,在编程时,双倍缓冲也比较容易计算 。
这样我们就回答了如上的两个问题 。迄今为止,我们有了一套彻底解决汉字和制表符相互干扰、半个汉字的刷新、重绘等问题的方案 。剩下的就是具体编程实现的问题了 。

推荐阅读