简介终端的两种工作模式:以行为单位的工作模式,以字符数或时间为单位自定义模式
终端判断函数:
- 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{
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:如果屏蔽此关键字,换行后缩进为上一行最后一个字符位置的后一位
- ECHO:回显,如果屏蔽则不显示输入的字符,像输入密码一样
- ICANON:行模式,屏蔽则变成自定义模式
- ISIG:使终端产生的信号(ctrl+c/ctrl+z等)起作用,屏蔽则忽略信号
- ICRNL:按下回车换行,屏蔽则不换行打印一个^M
- BRKINT:当在输入行中检测到一个终止状态时,产生一个中断
例子 1.行模式,关闭回显
#include
#include
#include
#include
#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 != '\n')
if(ptr < &buf[MAX_PASS_LEN])
*ptr++ = c;
*ptr=0;
putc('\n',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\n",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
#include
#include
#include
#include
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("\n%s\n",c);
}
return 0;
}