一、软件包的特点
ncurses软件包的目标是为字符终端和终端仿真器提供一个免费的软件API,具有以下特点:
* 与历史上的curses实现兼容(包括原始的BSD curses和System V curses)。
* 符合X/Open发布的XSI Curses标准。
* 高质量——稳定可靠的代码,广泛的可移植性,良好的包装和优秀的文档。
* 富有特色——应尽可能减少C接口编程的繁琐,使程序员能够以更高层次的设计思考。
这些目标按优先顺序排列。例如,与旧版本的源代码兼容性比功能丰富性更重要。
1)为什么选择System V Curses?
选择System V curses作为模型,通过逆向工程其API,以满足前两个目标。
System V curses实现可以通过重新编译来支持BSD curses程序,因此通过捕获System V API,我们也就捕获了BSD的API。
对于未来来说更重要的是,X/Open发布的XSI Curses标准明确且紧密地模仿了System V。
2)如何设计扩展
第三个目标(标准一致性)要求使用ncurses来对源代码进行条件编译,以便在没有非标准扩展的情况下不会破坏代码。 因此,策略是为每个非
标准扩展关联一个特性宏,以便ncurses客户端代码可以使用该宏来条件编译需要ncurses扩展的代码。
例如,有一个宏NCURSES_MOUSE_VERSION,它在XSI Curses中没有定义,但在ncurses库头文件中定义。您可以使用它来条件编译对鼠标API
的调用。
3)可移植性和配置
编写ncurses的代码可以假定存在一个符合ANSI标准的C编译器和POSIX兼容的操作系统接口。使用GNU autoconf(1)作为处理可移植性问题的工
具。利用特定于操作系统的功能的正确方法是修改autoconf规范文件(configure.in和aclocal.m4),设置一个新的特性宏,然后在代码中使用它。
二、库概述
大部分库都是上层结构,相当于一组用于操作虚拟屏幕的基本函数和数据结构的便利接口(特别是,在下面描述的更基本的模块中,这些代码都不进行任何I/O操作)。以下是几个文件的清单:
lib_addch.c lib_bkgd.c lib_box.c lib_chgat.c lib_clear.c
lib_clearok.c lib_clrbot.c lib_clreol.c lib_colorset.c lib_data.c
lib_delch.c lib_delwin.c lib_echo.c lib_erase.c lib_gen.c
lib_getstr.c lib_hline.c lib_immedok.c lib_inchstr.c lib_insch.c
lib_insdel.c lib_insstr.c lib_instr.c lib_isendwin.c lib_keyname.c
lib_leaveok.c lib_move.c lib_mvwin.c lib_overlay.c lib_pad.c
lib_printw.c lib_redrawln.c lib_scanw.c lib_screen.c lib_scroll.c
lib_scrollok.c lib_scrreg.c lib_set_term.c lib_slk.c
lib_slkatr_set.c lib_slkatrof.c lib_slkatron.c lib_slkatrset.c
lib_slkattr.c lib_slkclear.c lib_slkcolor.c lib_slkinit.c
lib_slklab.c lib_slkrefr.c lib_slkset.c lib_slktouch.c lib_touch.c
lib_unctrl.c lib_vline.c lib_wattroff.c lib_wattron.c lib_window.c
这些文件都属于这个类别。除非出现错误或者基础数据结构进行了根本性的重新组织,否则它们都不太可能需要更改。
这些文件仅用于调试支持:
lib_trace.c lib_traceatr.c lib_tracebits.c lib_tracechr.c
lib_tracedmp.c lib_tracemse.c trace_buf.c
除非出于某种原因想要引入新的调试跟踪级别,否则很少需要更改这些文件。
还有一组文件通过tputs()进行直接的I/O操作,对终端功能进行计算或向操作系统环境进行查询,但复杂度相对较低。包括:
lib_acs.c lib_beep.c lib_color.c lib_endwin.c lib_initscr.c
lib_longname.c lib_newterm.c lib_options.c lib_termcap.c lib_ti.c
lib_tparm.c lib_tputs.c lib_vidattr.c read_entry.c.
只有在将ncurses移植到不具备底层terminfo功能表示的环境时,才可能需要对这些文件进行修订。
这些文件与tty驱动程序和信号设施紧密相关:
lib_kernel.c lib_baudrate.c lib_raw.c lib_tstp.c lib_twait.c
如果在将软件包移植到另一个UNIX系统时遇到问题,问题很可能出现在这些文件中。文件lib_print.c也属于这个类别,它使用了sleep(2)。
实际上,大部分工作都是在以下文件中完成的:
hardscroll.c hashmap.c lib_addch.c lib_doupdate.c lib_getch.c
lib_mouse.c lib_mvcur.c lib_refresh.c lib_setup.c lib_vidattr.c
库的大部分算法复杂性都存在于这些文件中。如果在ncurses本身中存在真正的错误,那么很可能就在这里。下面我们将详细介绍其中一些文件
(请参阅引擎模块)。
三、引擎模块
1)键盘输入
所有的ncurses输入都通过lib_getch.c中定义的函数wgetch()进行处理。这个函数非常复杂;它必须对键盘和鼠标事件进行轮询,并将输入与定
义的特殊键集合进行匹配。
这个模块的核心数据结构是一个FIFO队列,用于将多字符输入序列与特殊键能力进行匹配,同时通过ungetch()实现退回操作。
wgetch()代码区分功能键序列和手动输入的相同序列,它在每个输入字符之后进行定时等待,以判断是否可能生成了功能键序列。
2) 鼠标事件
如果鼠标接口处于活动状态,wgetch()在每次调用之前都会轮询鼠标事件,然后再进行键盘输入。lib_mouse.c决定了轮询是如何实现的,对于
不同的设备可能会有所不同。
然而,在xterm下,鼠标事件通知是通过键盘输入流传入的。通过在函数键能力中添加kmous前缀来识别它们。这有点笨拙,但是如果不经过函
数键处理机制直接识别鼠标键前缀,将会非常痛苦,而且这意味着在终端类型初始化时必须在函数键能力中的某个位置添加前缀。