POSIX.1定义了11个在输入时作特殊处理的字符。实现定义了另外一些特殊字符。表18-6摘要列出了这些特殊字符。
表18-6 终端特殊输入字符
在POSIX.1的11个特殊字符中,可将其中9个更改为几乎任何值。不能更改的两个特殊字符是换行符和回车符(\n和\r),有些实现也不允许更改STOP和START字符。为了进行修改,只要更改termios结构中c_cc数组的相应项。该数组中的元素都用名字作为下标进行引用,每个名字都以字母V开头。
POSIX.1允许禁用这些字符。若将c_cc数组中的某项设置为_POSIX_VDISABLE的值,则禁用相应的特殊字符。
实例
在详细说明各特殊字符之前,先看一个更改特殊字符的程序。程序清单18-1禁用中断字符,并将文件结束符设置为Ctrl+B。
程序清单18-1 禁用中断字符和更改文件结束字符
#include "apue.h"
#include <termios.h>
int
main(void)
{
struct termios term;
long vdisable;
if(iastty(STDIN_FILENO) == 0)
err_quit("standard input is not a terminal device");
if((vdisable = fpathconf(STDIN_FILENO, _PC_VDISABLE)) < 0)
err_quit("fpathconf error or _POSIX_VDISABLE not in effect");
if(tcgetattr(STDIN_FILENO, &term) < 0) /* fetch tty state */
err_sys("tcgetattr error");
term.c_cc[VINTR] = vdisable; /* disable INTR character */
term.c_cc[VEOF] = 2; /* EOF is Control-B */
if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) < 0)
err_sys("tcsetattr error");
exit(0);
}
对此程序要说明以下几点:
- 仅当标准输入是终端设备时才修改终端特殊字符。调用isatty对此进行检测。
- 用fpathconf取_POSIX_VDISABLE值。
- 函数tcgetattr从内核取termios结构。在修改了此结构后,调用tcsetattr函数设置属性,这样就可以进行我们所希望的修改,而其他属性则保持不变。
- 禁用中断键与忽略中断信号是不同的。程序清单18-1所做的是禁止使用使终端驱动程序产生SIGINT信号的特殊字符。但仍可使用kill函数向进程发送该信号。
下面较详细地说明各个特殊字符。我们称这些字符为特殊输入字符,但是其中STOP和START(Ctrl+S和Ctrl+Q)两个字符在输出时也对它们进行特殊处理。注意,这些字符中的大多数在被终端驱动程序识别并进行特殊处理后都被丢弃,并不将它们传送给执行读终端操作的进程。例外的字符是换行符(NL,EOL,EOL2)和回车符(CR)。
CR 回车符。不能更改此字符。以规范模式进行输入时识别此字符。当设置了ICANON(规范模式)和ICRNL(将CR映射为NL)并且没有设置IGNCR(忽略CR)时,将CR转换成NL,并产生于NL符相同的作用。此字符返回给读进程(多半是转换成NL后)。
DISCARD 删除符。在扩充模式下(IEXTEN),在输入中识别此字符。在输入另一个DISCARD符之前或删除条件被清除之前(见FLUSHO选项),此字符使后续输出都被删除。在处理后此字符即被删除,不送向读进程。
DSUSP 延迟-挂起作业控制字符(delayed-suspend job-control character)。在扩充方式下,若支持作业控制并且ISIG标志被设置,则在输入中识别此字符。与SUSP字符的相同处是:延迟-挂起字符产生SIGTSTP信号,它被送至前台进程组中的所有进程。但是延迟-挂起字符产生信号的时间并不是在键入此字符时,而是在一个进程读控制终端读到此字符时。在处理后,此字符即被删除,不送向读进程。
EOF 文件结束符。以规范模式(ICANON)进行输入时识别此字符。当键入此字符时,等待被读的所有字节都立即传送给读进程。如果没有字节等待读,则返回0。在行首输入一个EOF符是向程序指示文件结束的正常方式。在以规范模式处理后,此字符即被删除,不送向读进程。
EOL 附加的行定界符,与NL作用相同。以规范模式(ICANON)进行输入时识别此字符,并将此字符返回给读进程。但通常不使用此字符。
EOL2 另一个行定界符,与NL作用相同。对此字符的处理方式与EOL字符相同。
ERASE 擦除字符(退格)。以规范模式(ICANON)输入时识别此字符。它擦除行中的前一个字符,但不会超越行首字符擦除上一行中的字符。在以规范模式处理后此字符即被删除,不送向读进程。
ERASE2 另一个擦除字符(退格)。对此字符的处理与ERASE完全相同。
INTR 中断字符。若设置了ISIG标志,则在输入中识别此字符。它产生SIGINT信号,该信号被送至前台进程组中的所有进程。在处理后,此字符即被删除,不送向读进程。
KILL kill(杀死)字符。(名字"杀死"在这里又一次被误用,会议kill函数,它将一个信号发送给进程。此字符应被称为行擦除符,它与信号毫无关系。)以规范模式(ICANON)输入时识别此字符。它擦除一整行。在处理后,此字符即被删除,不送向读进程。
LNEXT "字面上的下一个"字符(literal-next character)。以扩充方式(IEXTEN)输入时识别此字符,它使下一个字符的任何特殊含义都被忽略。使用这一字符可向程序键入任何字符。在处理后,LNEXT字符即被删除,但输入的下一个字符(即使是特殊字符)则被传送给读进程。
NL 新行字符,它也被称为行定界符。不能更改此字符。以规范模式(ICANON)输入时识别此字符。此字符返回给读进程。
QUIT 推出字符。若设置了ISIG标志,则在输入中识别此字符。它产生SIGQUIT信号,该信号又被送至前台进程组中的所有进程。在处理后,此字符即被删除,不送向读进程。
REPRINT 再打印字符。以扩充规范模式(设置了IEXTEN和ICANON标志)进行输入时识别此字符。它使所有未读的输入被输出(再回显)。在处理后,此字符即被删除,不送向读进程。
START 启动字符。若设置了IXON标志则在输入中识别此字符;若设置IXOFF标志则作为输出自动产生此字符。在IXON已设置时接收到的START字符使停止的输出(由以前输入的STOP字符造成的)重新启动。在此情形下,此字符处理后即被删除,不送向读进程。在IXOFF标志被设置时,若输入不会使输入缓冲区溢出,则终端驱动程序自动地产生一START字符以恢复以前被停止的输入。
STATUS BSD的状态-请求字符。以扩充规范模式(设置IEXTEN和ICANON标志)进行输入时识别此字符。它产生SIGINFO信号,该信号又被送至前台进程组中的所有进程。另外,如果没有设置NOKERNINFO标志,则有关前台进程组的状态信息也显示在终端上。在处理后,此字符即被删除,不送向读进程。
STOP 停止字符。若设置了IXON标志,则在输入中识别此字符;若IXOFF标志已设置则作为输出自动产生此字符。在IXON已设置时接受到STOP字符则停止输出。在此情形下,处理后删除此字符,不送向读进程。当输入一个START字符后,停止的输出重新启动。在IXOFF设置时,终端驱动程序自动地产生一个STOP字符以防止输入缓冲区溢出。
SUSP 挂起作业控制字符。若支持作业控制并且ISIG标志已设置,则在输入中识别此字符。它产生SIGTSTP信号,该信号又被送至前台进程组的所有进程。在处理后,此字符即被删除,不送向读进程。
WERASE 字擦除字符。以扩充规范模式(设置IEXTEN和ICANON标志)进行输入时识别此字符。它擦除前一个字。首先,它向后跳过任一空白字符(空格或制表符),然后再向后越过前一个记号(token),使光标处在前一个记号的第一个字符位置上。通常,前一个记号在碰到一个空白字符时即终止。但是,可用设置ALTWERASE标志来改变这一点。此标志使前一个记号在碰到第一个非字母、数字符时即终止。在处理后,此字符即被删除,不送向读进程。
需要为终端设备定义的另一个"字符"是BREAK。BREAK实际上并不是一个字符,而是在异步串行数据传送时发生的一个条件。依赖于串行接口,可以有多种方式通知设备驱动程序发生了BREAK条件。
对于异步串行数据传送,BREAK是一个0值的位序列,其持续时间长于要求发送一个字节的时间。整个0值位序列被视为是一个BREAK。