struct winsize{ unsigned short ws_row; // rows, in characters unsigned short ws_col; // columns, in characters unsigned short ws_xpixel; // horizontal size, pixels (unused) unsigned short ws_ypixel; // vertical size, pixels (unused) };
此结构的规则如下:
1、用 ioctl 函数(见 终端I/O函数 ioctl一节)的 TIOCGWINSZ 命令可以取此结构的当前值。
2、用 ioctl 的 TIOCSWINSZ 命令可以将此结构的新值存储到内核中。如果此新值与存储在内核中的当前值不同,则将向前台进程组发送 SIGWINCH 信号(默认会被忽略)。
3、除了存储此结构的当前值以及在此值改变时产生一个信号以外,内核对该结构不进行任何其他操作。对结构中的值进行解释是应用程序的工作。
提供这种功能的目的是,当窗口大小发生变化时应用程序能得到通知(如 vi 编辑器)。应用程序接收到此信号后,可以获取窗口大小的新值,然后重绘屏幕。
下面这个程序会打印当前窗口大小,然后休眠。之后每次窗口大小改变时,程序就捕捉 SIGWINCH 信号,然后打印新的窗口大小。
#include#include #include #include #ifndef TIOCGWINSZ #include #endif static void pr_winsize(int fd){ struct winsize size; if(ioctl(fd, TIOCGWINSZ, (char *)&size) < 0){ printf("TIOCGWINSZ error\n"); exit(1); } printf("%d rows, %d columns\n", size.ws_row, size.ws_col); } static void sig_winch(int signo){ printf("SIGWINCH received\n"); pr_winsize(STDIN_FILENO); } int main(void){ if(isatty(STDIN_FILENO) == 0) exit(1); if(signal(SIGWINCH, sig_winch) == SIG_ERR){ printf("signal error\n"); exit(1); } pr_winsize(STDIN_FILENO); // print initial size for(;;) // and sleep forever pause(); }
termcap 的意思是终端能力(terminal capability),它涉及文本文件 /etc/termcap 和一套读此文件的例程,主要是为了支持 vi 编辑器而开发的。termcap 文件包含了对各种终端的说明:终端支持哪些功能(如行数、列数、是否支持退格)、如何使终端执行某些操作(如清屏、移动光标到指定位置)等。把这些信息从编译过的程序中取出来并把它们放在易于编辑的文本文件中,这样就使得 vi 编辑器能在很多不同的终端上运行。最后,将支持 termcap 文件的例程从 vi 编辑器中抽取出来,放在一个单独的 curses 库中。为使这套库可供要进行屏幕处理的任何程序使用,还增加了很多功能。
不过 termcap 这种技术并不是很完善。因为当越来越多的终端被加到数据文件中时,为找到一个特定的终端,可能需要花费很长的时间扫描此数据文件。另外,该数据文件还用两个字符的名字来标识不同的终端属性。因此出现了 terminfo 以及与其相关的 curses 库。在 terminfo 中,终端说明基本上都是文本说明的编译版本,在运行时易于被快速定位。
但不论是 termcap 还是 terminfo,它们本身都只提供在各种终端上执行典型操作(如清屏、移动光标等)的方法,而不处理如更改终端模式、更改终端特殊字符、处理窗口大小等问题。不过 curses 库能提供某种具体细节方面的帮助。它提供了很多函数,用来设置原始模式、设置 cbreak 模式、打开和关闭回显等。注意,curses 库是为基于字符的哑终端设计的,它们如今大部分已被基于像素的图像终端所代替。