终端IO部分整体上读了两遍,感觉这一部分的内容又乱又碎,不太好理解。读完了之后,仍然感觉什么也没有学到。先做一个肤浅的记录,等到以后要用到的时候,再回来补充。
终端IO有两种不同的工作方式,规范方式输入处理和非规范方式输入处理:
(1)规范方式输入处理:终端以行为单位进行处理,对于每个读要求,终端驱动程序最多返回一行。 (2)非规范方式输入处理:输入字符不以行为单位进行处理。
终端设备是由位于内核中的终端驱动程序所控制的,每个终端设备有一个输入队列和一个输出队列。
关于终端IO的属性存放在一个 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 */
int tcgetattr(int fd, struct termios *termios_p); int tcsetattr(int fd, int optional_actions,const struct termios *termios_p); int tcsendbreak(int fd, int duration); int tcdrain(int fd); int tcflush(int fd, int queue_selector); int tcflow(int fd, int action); speed_t cfgetispeed(const struct termios *termios_p); speed_t cfgetospeed(const struct termios *termios_p); int cfsetispeed(struct termios *termios_p, speed_t speed); int cfsetospeed(struct termios *termios_p, speed_t speed);
下面的一个例子用来禁止终端中的中断字符(即CTRL+C),并且将文件结束的字符更改为CTRL+B:
#include <termios.h> #include <stdio.h> #include <unistd.h> int main(void) { struct termios term; long vdisable; if(isatty(STDIN_FILENO)==0) { printf("standard input is not terminal device\n"); return -1; } if( (vdisable=fpathconf(STDIN_FILENO,_PC_VDISABLE))<0 ) { printf("fpathconf error\n"); return -1; } if(tcgetattr(STDIN_FILENO,&term)<0) { printf("tcgetattr error\n"); return -1; } term.c_cc[VINTR] = vdisable; term .c_cc[VEOF] = 2; if(tcsetattr(STDIN_FILENO,TCSAFLUSH,&term)<0) { printf("tcsetattr error\n"); return -1; } return 0; }
该程序先用 isatty 函数来测试 STDIN_FILENO 描述符所指向的文件是否是终端设备,如果测试的文件描述符是指向一个终端设备的话则返回1,否则返回0。
然后使用函数 fpathconf 获取系统中的 _PC_VDISABLE 的值,将这个值保存在 c_cc 数组中的相应位置就可以禁止使用这个位置所代表的特殊字符。
接着我们调用 tcgetattr 函数用来获取终端IO的属性,然后设置 c_cc 数组的 VINTR 的位置为 _PC_VDISABLE,表示禁止使用中断符号CTRL+C。而将VEOF的位置的值更改为2,即表示将文件的结束符号修改为CTRL+B,同理如果要修改为CTRL+A,则这个地方的值为1。
最后使用 tcsetattr 函数设置修改过的属性,使这些属性生效。tcsetattr 函数的第二个参数用来表示设置属性之后,这些属性生效的时间,这个参数有三种选择:
TCSANOW:更改立即生效 TCSADRAIN:发送了所有输出之后,更改才生效。如果更改输出参数,则应该使用此选项。 TCSAFLUSH:发送了所有输出之后,更改才生效。这里和上面一个的不同是,当更改发生时,未读的所有输入数据都被删除(丢弃)。
(1)ctermid 函数用来返回控制终端的名字,一般是 /dev/tty。它的函数原型如下:
#include <stdio.h> char *ctermid(char *s);
#include <stdio.h> #include <string.h> static char ctermid_name[L_ctermid]; char* ctermid(char* str) { if(str==NULL) { str = ctermid_name; } return strcpy(str,"/dev/tty"); //strcpy returns str }
(2)isatty 函数的一种实现如下:
#include <termios.h> #include <stdio.h> int isatty(int fd) { struct termios term; return (tcgetattr(fd,&term)!=-1); }
#include <termios.h> #include <stdio.h> int isatty(int fd) { struct termios term; return (tcgetattr(fd,&term)!=-1); } int main(void) { printf("fd 0:%s\n",isatty(0)?"tty":"not a tty"); printf("fd 1:%s\n",isatty(1)?"tty":"not a tty"); printf("fd 2:%s\n",isatty(2)?"tty":"not a tty"); return 0; }
fd 0:tty fd 1:tty fd 2:tty
./a.out</etc/passwd 2>/tmp/t
fd 0:not a tty fd 1:tty fd 2:not a tty
(3)ttyname 返回在指定描述符上打开的终端设备的路径名,例如下面的一个程序可以演示一下它的使用:
#include <unistd.h> #include <stdio.h> int main(void) { printf("fd 0:%s\n",isatty(0)?ttyname(0):"not a tty"); printf("fd 1:%s\n",isatty(1)?ttyname(1):"not a tty"); printf("fd 2:%s\n",isatty(2)?ttyname(2):"not a tty"); return 0; }
linux 系统提供了一个跟踪终端大小的功能,内核为每个终端或者是伪终端保存了一个 winsize 结构体,这个结构体中保存了当前终端大小的信息,这个结构体如下:
struct winsize { unsigned short ws_row; unsigned short ws_col; unsigned short ws_xpixel; unsigned short ws_ypixel; };
#include <signal.h> #include <termios.h> #ifndef TIOCGWINSZ #include <sys/ioctl.h> #endif #include <stdio.h> #include <stdlib.h> #include <unistd.h> static void pr_winsize(int fd) { struct winsize size; if(ioctl(fd,TIOCGWINSZ,(char*)&size)<0) { printf("TIOCGWINSZ error\n"); exit(-1); } printf("%d rows,%d columns\n",size.ws_row,size.ws_col); } static void sig_winch(int signo) { printf("SIGWINCH received\n"); pr_winsize(STDIN_FILENO); return; } int main(void) { if(isatty(STDIN_FILENO)==0) { exit(1); } if(signal(SIGWINCH,sig_winch)==SIG_ERR) { printf("signal error\n"); return -1; } pr_winsize(STDIN_FILENO); for(;;) { pause(); } }
55 rows,178 columns SIGWINCH received 6 rows,63 columns SIGWINCH received 6 rows,124 columns SIGWINCH received 24 rows,124 columns SIGWINCH received 53 rows,178 columns SIGWINCH received 55 rows,178 columns
原文:http://blog.csdn.net/xiaocainiaoshangxiao/article/details/18270215