《Linux編程技術詳解》第6章的主要內容是設備文件,本小節講的是使用tcgetattr函數與tcsetattr函數控制終端。
6.4.4 使用tcgetattr函數與tcsetattr函數控制終端
爲了便於通過程序來獲得和修改終端參數,Linux還提供了tcgetattr函數和tcsetattr函數。tcgetattr用於獲取終端的相關參數,而tcsetattr函數用於設置終端參數。這兩個函數的具體信息如表6.2所示。
表6.2 tcgetattr函數和tcsetattr函數
頭文件 |
<termios.h> <unistd.h> |
||
函數形式 |
int tcgetattr(int fd, struct termios *termios_p); int tcsetattr(int fd, int optional_actions, const struct termios *termios_p); |
||
返回值 |
成功 |
失敗 |
是否設置errno |
0 |
−1 |
是 |
說明:tcgetattr函數用於獲取與終端相關的參數。參數fd爲終端的文件描述符,返回的結果保存在termios結構體中,該結構體一般包括如下的成員:
tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t c_cc[NCCS]; |
其具體意義如下。
c_iflag:輸入模式標誌,控制終端輸入方式,具體參數如表6.3所示。
表6.3 c_iflag參數表
鍵 值 |
說 明 |
IGNBRK |
忽略BREAK鍵輸入 |
BRKINT |
如果設置了IGNBRK,BREAK鍵的輸入將被忽略,如果設置了BRKINT ,將產生SIGINT中斷 |
IGNPAR |
忽略奇偶校驗錯誤 |
PARMRK |
標識奇偶校驗錯誤 |
INPCK |
允許輸入奇偶校驗 |
ISTRIP |
去除字符的第8個比特 |
INLCR |
將輸入的NL(換行)轉換成CR(回車) |
IGNCR |
忽略輸入的回車 |
ICRNL |
將輸入的回車轉化成換行(如果IGNCR未設置的情況下) |
IUCLC |
將輸入的大寫字符轉換成小寫字符(非POSIX) |
IXON |
允許輸入時對XON/XOFF流進行控制 |
IXANY |
輸入任何字符將重啓停止的輸出 |
IXOFF |
允許輸入時對XON/XOFF流進行控制 |
IMAXBEL |
當輸入隊列滿的時候開始響鈴,Linux在使用該參數而是認爲該參數總是已經設置 |
c_oflag:輸出模式標誌,控制終端輸出方式,具體參數如表6.4所示。
表6.4 c_oflag參數
鍵 值 |
說 明 |
OPOST |
處理後輸出 |
OLCUC |
將輸入的小寫字符轉換成大寫字符(非POSIX) |
ONLCR |
將輸入的NL(換行)轉換成CR(回車)及NL(換行) |
OCRNL |
將輸入的CR(回車)轉換成NL(換行) |
ONOCR |
第一行不輸出回車符 |
ONLRET |
不輸出回車符 |
OFILL |
發送填充字符以延遲終端輸出 |
OFDEL |
以ASCII碼的DEL作爲填充字符,如果未設置該參數,填充字符將是NUL(‘\0’)(非POSIX) |
NLDLY |
換行輸出延時,可以取NL0(不延遲)或NL1(延遲0.1s) |
CRDLY |
回車延遲,取值範圍爲:CR0、CR1、CR2和 CR3 |
TABDLY |
水平製表符輸出延遲,取值範圍爲:TAB0、TAB1、TAB2和TAB3 |
BSDLY |
空格輸出延遲,可以取BS0或BS1 |
VTDLY |
垂直製表符輸出延遲,可以取VT0或VT1 |
FFDLY |
換頁延遲,可以取FF0或FF1 |
c_cflag:控制模式標誌,指定終端硬件控制信息,具體參數如表6.5所示。
表6.5 c_oflag參數
鍵 值 |
說 明 |
CBAUD |
波特率(4+1位)(非POSIX) |
CBAUDEX |
附加波特率(1位)(非POSIX) |
CSIZE |
字符長度,取值範圍爲CS5、CS6、CS7或CS8 |
CSTOPB |
設置兩個停止位 |
CREAD |
使用接收器 |
PARENB |
使用奇偶校驗 |
PARODD |
對輸入使用奇偶校驗,對輸出使用偶校驗 |
HUPCL |
關閉設備時掛起 |
CLOCAL |
忽略調制解調器線路狀態 |
CRTSCTS |
使用RTS/CTS流控制 |
c_lflag:本地模式標誌,控制終端編輯功能,具體參數如表6.6所示。
表6.6 c_lflag參數
鍵 值 |
說 明 |
ISIG |
當輸入INTR、QUIT、SUSP或DSUSP時,產生相應的信號 |
ICANON |
使用標準輸入模式 |
XCASE |
在ICANON和XCASE同時設置的情況下,終端只使用大寫。如果只設置了XCASE,則輸入字符將被轉換爲小寫字符,除非字符使用了轉義字符(非POSIX,且Linux不支持該參數) |
ECHO |
顯示輸入字符 |
ECHOE |
如果ICANON同時設置,ERASE將刪除輸入的字符,WERASE將刪除輸入的單詞 |
ECHOK |
如果ICANON同時設置,KILL將刪除當前行 |
ECHONL |
如果ICANON同時設置,即使ECHO沒有設置依然顯示換行符 |
ECHOPRT |
如果ECHO和ICANON同時設置,將刪除打印出的字符(非POSIX) |
TOSTOP |
向後臺輸出發送SIGTTOU信號 |
c_cc[NCCS]:控制字符,用於保存終端驅動程序中的特殊字符,如輸入結束符等。c_cc中定義瞭如表6.7所示的控制字符。
表6.7 c_cc支持的控制字符
宏 |
說 明 |
宏 |
說 明 |
VINTR |
Interrupt字符 |
VEOL |
附加的End-of-file字符 |
VQUIT |
Quit字符 |
VTIME |
非規範模式讀取時的超時時間 |
VERASE |
Erase字符 |
VSTOP |
Stop字符 |
VKILL |
Kill字符 |
VSTART |
Start字符 |
VEOF |
End-of-file字符 |
VSUSP |
Suspend字符 |
VMIN |
非規範模式讀取時的最小字符數 |
|
|
tcsetattr函數用於設置終端的相關參數。參數fd爲打開的終端文件描述符,參數optional_actions用於控制修改起作用的時間,而結構體termios_p中保存了要修改的參數。
optional_actions可以取如下的值。
TCSANOW:不等數據傳輸完畢就立即改變屬性。
TCSADRAIN:等待所有數據傳輸結束才改變屬性。
TCSAFLUSH:清空輸入輸出緩衝區才改變屬性。
錯誤信息:
EBADF:非法的文件描述符。
EINTR:tcsetattr函數調用被信號中斷。
EINVAL:參數optional_actions使用了非法值,或參數termios中使用了非法值。
ENCTTY:非終端的文件描述符。
實例演練:
程序p6.2.c通過修改終端控制字符,將終端輸入結束符由“Ctrl+D”,修改成了“Ctrl+G”。首先,程序調用tcgetattr函數獲得標準輸入的termios信息,將termios結構體中的c_cc[VEOF]控制字符的修改成0x07(即Ctrl+G);然後,使用tcsetattr函數將修改後的termios參數設置到終端中。具體代碼如下所示:
//p6.2.c 修改終端控制字符示例 #include <stdio.h> #include <termios.h> #include <unistd.h> #include <errno.h> int main(void){ //term用於存儲獲得的終端參數信息 struct termios term; int err; //獲得標準輸入的終端參數,將獲得的信息保存在term變量中 if(tcgetattr(STDIN_FILENO,&term)==-1){ perror("Cannot get standard input description"); return 1; } //修改獲得的終端信息的結束控制字符 term.c_cc[VEOF]=(cc_t)0x07; //使用tcsetattr函數將修改後的終端參數設置到標準輸入中 //err用於保存函數調用後的結果 err=tcsetattr(STDIN_FILENO,TCSAFLUSH,&term); //如果err爲-1或是出現EINTR錯誤(函數執行被信號中斷), //給出相關出錯信息 if(err==-1 && err==EINTR){ perror("Failed to change EOF character"); return 1; } return 0; } |
使用gcc編譯p6.2.c程序,得到名爲p6.2的可執行程序。在執行p6.2程序前,按“Ctrl+D”可以使終端結束。執行p6.2程序後,按“Ctrl+D”失去了作用,而輸入“Ctrl+G”實現了原來“Ctrl+D”的功能。