Linux下程式輸入輸出(^H、^C問題)
問題:
1、在linux的遠端終端上執行程式出現個人開發的應用按backspace鍵時有^H等不識別字符;
2、在CentOS7下的應用程式按backspace可以刪除但是delete鍵就無法實現像windows下的刪除後側的字元;
3、在linux下的應用如果要使用類似shell實現自己應用的歷史記錄時,方向鍵無法識別,出現:^[[A、^[[B等字元,Tab鍵依舊沒有辦法識別;
4、輸入回車時列印很多空行,不會有任何提示或者類似linux 的終端列印;
解決方法:
1、設定遠端工具的引數,以SecureCRT為例:
1.1、 依次選擇“選項”
其他版本的SecurtCRT查詢相似的選項。
1.2、設定SecurtCRT的終端模式:
Linux支援Linux、VT100、VT200等終端模式,Linux舊的終端模式需要Ctrl+Backspace才能刪除字元,因此後期推出了VT100的終端模式,但是VT100中字元編碼混亂以至於Delete和BackSpace鍵不能嚴格區分,因此Linux的某些程式碼中含有註釋:magic shit
^H出現時,切換SecurtCRT的終端模式實現鍵值對映,如下:
圖2.選擇SecurtCRT連線Linux的終端模式
一般選擇VT100,此時的BackSpace鍵和Delete鍵需要對映一致否則Linux在使用者寫的命令列模式下沒有辦法識別Delete鍵。
2、在Linux的應用程式中實現ReadLine和EditLine,使應用程式執行時不會出現鍵值無法識別的情況
原始碼參考:
程式碼實現總體思路:
i.首先解除現有Linux終端的引數設定,使終端引數迴歸到最簡單的模式;
ii.其次,通過標準輸入輸出裝置讀取字元流和重新整理字元流,從而實現scanf和printf兩個函式;
iii.在讀寫標準裝置完成後,恢復終端原有的模式,使其他依賴當前終端的應用程式不會跑飛或出現異常。
2.1、終端設定標頭檔案:
#include <termios.h> #include <unistd.h>
相關結構體:
struct termios
{
tcflag_t c_iflag; /* input modes 輸入模式 */ tcflag_t c_oflag; /* output modes 輸出模式 */ tcflag_t c_cflag; /* control modes 控制模式*/ tcflag_t c_lflag; /* local modes 本地模式 */ cc_t c_cc[ NCCS ] ; /* special characters 特殊字元控制 * /
};
結構體各引數取值描述可以通過在Linux下查詢對應的函式,如:man tcgetattr
2.2、讀取標準輸入裝置的字元
char input;
read(STDIN_FILENO,&input,1);
2.3、向標準輸出裝置寫入字元重新整理到螢幕上
char output[100];
write(STDOUT_FILENO,output,strlen(output));
2.4、改造後的Readline和Editline的實現
分三個檔案:read_line.c、read_line.h及main.c
a.read_line.c檔案內容如下:
/*********************************************************************
* 檔名:read_line.c
* 描述: C語言實現的簡易readline
* 時間: 2018-11-11
* 建立: Firdin
* 郵箱: [email protected]
*
* 修改歷史:
* 版本 時間 作者 內容
-----------------------------------------------------
* V0.1 2018-11-11 firdin 從github上移植,編碼:UTF-8
*
*********************************************************************/
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "read_line.h"
b.read_line.h檔案內容如下:
#ifndef _READ_LINE_H
#define _READ_LINE_H
#define READLINE_DEFAULT_HISTORY_MAX_LEN 100
#define READLINE_MAX_READLINE_BUFFER_SIZE 4096
/* readline依賴的資料結構體 */
typedef struct
{
int ifd; /* 當前終端標準輸入檔案描述符 */
int ofd; /* 當前終端標準輸出檔案描述符 */
char *buf; /* 行buffer指標 */
size_t buflen; /* 行buffer長度 */
const char *prompt; /* 字首顯示內容buffer指標 */
size_t plen; /* 字首長度 */
size_t pos; /* 當前游標位置 */
size_t oldpos; /* 重新整理前游標位置 */
size_t len; /* 正在編輯的行長度 */
size_t cols; /* 終端列數 */
size_t maxrows; /* 多行顯示時,記錄當前剩餘行數 */
int history_index; /* 命令列歷史記錄指標 */
}readline_db_t;
/* 鍵值表,可以通過鍵值工具獲取想要新增的組合鍵的鍵值 */
enum key_value
{
KEY_NULL = 0, /* NULL */
CTRL_A = 1, /* Ctrl+a */
CTRL_B = 2, /* Ctrl-b */
CTRL_C = 3, /* Ctrl-c */
CTRL_D = 4, /* Ctrl-d */
CTRL_E = 5, /* Ctrl-e */
CTRL_F = 6, /* Ctrl-f */
CTRL_H = 8, /* Ctrl-h */
TAB = 9, /* Tab */
CTRL_K = 11, /* Ctrl+k */
CTRL_L = 12, /* Ctrl+l */
ENTER = 13, /* Enter */
CTRL_N = 14, /* Ctrl-n */
CTRL_P = 16, /* Ctrl-p */
CTRL_T = 20, /* Ctrl-t */
CTRL_U = 21, /* Ctrl+u */
CTRL_W = 23, /* Ctrl+w */
ESC = 27, /* Escape */
BACKSPACE = 127 /* Backspace */
};
#endif /* End of _READ_LINE_H */
c.main.c示例應用檔案內容如下:
以上程式碼遵循GNU開源精神,如有不適處請多加指正,多謝。
待補充完善