linux终端io笔记

简介

终端的两种工作模式:以行为单位的工作模式,以字符数或时间为单位自定义模式
终端判断函数:

  • int isatty(int fd)

终端属性的获取与设置:

  • int tcgetattr(int fd,struct termios *termptr)
  • int tcsetattr(int fd,int opt,const struct termios *termptr),opt选项如下
    TCSANOW:不等数据传输完毕就立即改变属性。
    TCSADRAIN:等待所有数据传输结束才改变属性。
    TCSAFLUSH:等待所有数据传输结束,清空输入输出缓冲区才改变属性。

终端名称的获取:

  • char *ctermid(char *ptr),如果ptr非空,则将终端名称(/dev/tty)写入到此ptr中并返回;若为空,分配空间写入后返回

终端属性结构:struct termios

struct termios{ 
           tcflag_t c_iflag; 
           tcflag_t c_oflag; 
           tcflag_t c_cflag; 
           tcflag_t c_lflag; 
           cc_t c_cc[NCCS]; 
};

termios关键字

c_oflag:控制输出格式

  • OPOST:如果屏蔽此关键字,换行后缩进为上一行最后一个字符位置的后一位

c_lflag:本地模式

  • ECHO:回显,如果屏蔽则不显示输入的字符,像输入密码一样
  • ICANON:行模式,屏蔽则变成自定义模式
  • ISIG:使终端产生的信号(ctrl+c/ctrl+z等)起作用,屏蔽则忽略信号

c_iflag:控制输入格式

  • ICRNL:按下回车换行,屏蔽则不换行打印一个^M
  • BRKINT:当在输入行中检测到一个终止状态时,产生一个中断

c_cc:见例2


例子

1.行模式,关闭回显

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
 
#define MAX_PASS_LEN 8
 
char * getpass(const char *prompt){
    static char buf[MAX_PASS_LEN+1];
    char *ptr;
    struct termios ts,ots;
    FILE *fp;
    int c;
 
    if((fp=fopen(ctermid(NULL),"r+")) == NULL)
        return 0;
    setbuf(fp,NULL);
 
    tcgetattr(fileno(fp),&ts);
    ots=ts;
    ts.c_lflag &= ~ECHO;
    tcsetattr(fileno(fp),TCSAFLUSH,&ts);
    fputs(prompt,fp);
 
//ptr < &buf[x] 两个内存地址比较,最多填充到buf[MAX_PASS_LEN-1]
//*ptr=0 在接下来的一位填充0表示结束
    ptr=buf;
    while((c=getc(fp)) != EOF && c != '
')
        if(ptr < &buf[MAX_PASS_LEN])
            *ptr++ = c;
    *ptr=0;
    putc('
',fp);
 
    tcsetattr(fileno(fp),TCSAFLUSH,&ots);
    fclose(fp);
    return buf;
}
 
int main(){
    char *ptr;
    if((ptr=getpass("Enter password:")) == NULL)
        perror("getpass word");
    printf("passowrd: %s
",ptr);
 
//先ptr++移到下一位置,接着ptr副本(未移动前的位置)进行*ptr=0
    while(*ptr != 0)
        *ptr++ =0;
    return 0;
}

2.自定义模式
将termios结构中c_lflag字段的ICANON标志关闭就使终端处于非行模式,此时回车换行不作为行结束标识返回
自定义模式下有两种结束标识:

  • c_cc数组中的VMIN变量即c_cc[VMIN]作为最少字符结束标识,字符达到VMIN个就返回,c_cc[VMIN]=0表示不限容量
  • c_cc数组中的VTIME变量即c_cc[VTIME]作为最短时间结束标识,从第一个字符输入开始,经过VTIME时间后就返回,c_cc[VTIME]=0表示不限时间

另外,也可以同时指定上述两个变量,只要有一个变量指定的条件成立就返回
以下为简单自定义模式,字符长度达到10就返回,对SIGINT中断做复位处理

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include <signal.h>
 
static struct termios save_termios;
static int ttysavefd=-1;
 
int tty_cbreak(int fd){
    struct termios buf;
    if(tcgetattr(fd,&save_termios) <0){
        perror("tcgetattr error");
        return -1;
    }
 
    buf=save_termios;
    buf.c_lflag &= ~ICANON;
    buf.c_iflag &= ~ICRNL;
    buf.c_cc[VMIN]=10;
    buf.c_cc[VTIME]=0;
 
    if(tcsetattr(fd,TCSAFLUSH,&buf) <0){
        perror("tcsetattr error");
        return -1;
    }
    ttysavefd=fd;
    return 0;
}
 
int tty_reset(int fd){
    if(tcsetattr(fd,TCSAFLUSH,&save_termios) <0){
        return -1;
    }
    return 0;
}

int main(int argc,char *argv[]){
    if(signal(SIGINT,sig_catch) == SIG_ERR)
        perror("signal error");
    if(tty_cbreak(STDIN_FILENO) <0)
        perror("tty_cbreak error");
    char c[11]={0};
    int i;
    puts("cbreak mode,terminate with sigint");
    while(i=read(STDIN_FILENO,&c,10)){
        printf("
%s
",c);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cfans1993/p/5581564.html