终端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