終端IO(上)

一、綜述

  終端IO有兩種不同的工作方式:

  • 規範方式輸入處理。在這種方式中,終端輸入以行爲單位進行處理。對於每個讀要求,終端驅動程序最多返回一行。
  • 非規範方式輸入處理。輸入字符不以行爲單位進行裝配

  如果不做特殊處理,則默認方式是規範方式。vi編輯程序使用非規範方式,其原因是其命令是由不以換行符終止的一個或幾個字符組成。
  POSIX.1定義了11個特殊輸入字符。其中9個可以改變
  終端設備一般位於內核中的終端驅動程序所控制的。每個終端設備有一個輸入隊列,一個輸出隊列,見下圖:
  

  對此圖要說明以下幾點:

  • 如果需要回送,則在輸入隊列和輸出隊列中間有一個隱含的連接。
  • 輸入隊列的長度MAX_INPUT是有限值,當一個特定設備的輸入隊列已填滿,各系統實現有所不同,大多數UNIX系統會送響鈴字符。
  • 圖中沒有顯示另一個輸入限制MAX_CANON,它是一個規範輸入行中的最大字節數。
  • 雖然輸出隊列通常也是有限長度,但是程序不能存取定義其長度的常數。這是因爲當輸出隊列要填滿時,內核使寫進程睡眠直至寫隊列中有可用的空間,所以程序無需關心該隊列的長度。

  大多數UNIX系統在一個稱爲終端行規程(terminal line discipline)的模塊中進行規範處理。它是位於內核類屬讀、寫函數和實際設備驅動程序之間的模塊,見下圖
  

  所有我們可以檢測和更改的終端設備特性都包含在termios結構中。該結構在頭文件<termios.h>中定義。

struct termios {
    tcflag_t    c_iflag; /* input flag */
    tcflag_t    c_oflag; /* output flags */
    tcflag_t    c_cflag; /* control flags */
    tcflag_t    c_lflag; /* local flags */
    cc_t        c_cc[NCCS]; /* control characters */
};

  粗略而言,輸入標誌由終端設備驅動程序用來控制輸入特性(剝除輸入字節第8位,允許輸入奇偶校驗等等),輸出標誌則控制輸出特性(執行輸出處理,將新行映照爲CR/LF等),控制標誌影響到RS-232串行線(忽略調制解調器的狀態線,每個字符的一個或兩個停止位等等),本地標誌影響驅動程序和用戶之間的界面(回送的開或關,可試的擦除符,允許終端產生的信號,對後臺作業輸出的控制停止信號等)。
  類型tcflag_t的長度是以保持每個標誌值。它經常被定義爲unsigned long。c_cc數組包含了所有可以更改的特殊字符。NCCS是該數組的長度,POSIX.1定義爲11,咯實現有所不同。cc_t類型的長度足以保持每個專用字符,典型的是unsigned char。
  下表列出了所有可以更改以影響終端設備特性的終端標誌。
  

  下表列出了POSIX.1定義對終端設備進行操作的各個函數。
  

  對終端設備,POSIX.1沒有使用ioctl,而使用了上表中列出的12個函數。這樣做的理由是:對於終端設備的ioctl函數,最後一個參數的數據類型隨執行動作的不同而不同。
  上表中12個函數之間的關係見下圖:
  

 

二、特殊輸入字符

  POSIX.1定義了11個在輸入時做特殊處理的字符。SVR4 另外加了6個特殊字符,4.3+BSD則加了7個。下表列出了這些字符
  

  11個特殊字符中,9個可以更改爲任何值。不能更改的是換行符\n和回車符\r。爲了進行修改,只要更改termios結構中c_cc數組的相應項。該數組中的元素都用名字作爲下標進行引用,每個名字都以字母V開頭。

三、獲取和設置終端屬性

  使用函數tcgetattr和tcsetattr可獲得/設置termios。這樣就可以檢測和修改各種終端選擇標誌和特殊字符,以使終端按我們所希望的方式進行操作。

#include <termios.h>
int tcgetattr(int filedes, struct termios *termpptr);
int tcsetattr(int filedes, int opt, const struct termios *termpptr);\
返回值: 成功爲1,出錯爲-1

  因爲這兩個函數只對終端設備進行操作,所以若filedes並不引用一個終端設備則出錯返回,error設置爲ENOTTY
  tcsetattr的參數opt使我們可以指定在什麼時候新的終端屬性才起作用。opt可以指定爲以下常數中的一個:

  • TCSANOW 更改立即發生
  • TCSADRAIN 發送了所有輸出後更改才發生。若更改輸出參數則應使用此選擇項
  • TCSAFLUSH 發送了所有輸出後更改才發生。更進一步,在更改發生時未讀的所有輸入數據都被刪除(刷清)。

  tcsetattr函數的返回值易於產生混淆。如果執行了任意一種所要求的動作,即使未能執行所有要求的動作,它也返回0(表示成功)。如果函數返回0,則我們有必要調用tcgetattr獲取實際終端屬性與希望的終端屬性做對比,判斷是否真正的修改成功。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章