linux下编程查看终端设置

这是《Unix/Linux编程实践教程》上第五章的第一个例子,编写showtty程序,可以显示终端的设置,如波特率、c_cc的VERASE位和VKILL以及input_flags和local_flags标志集。这里先谈一谈我的体会,代码及注释附在文末。显示效果如下:

1.如何实现?

有了读写文件的经验和读写目录的经验,就会发现终端的设置也是类似的,这些设置也存在一个结构体里,而通过相应的函数,就可把这个结构体如初来,由此就可以显示各项设置了。本程序实现过程就是如此,是不是很相似呢?

这里我们在这个程序基础之上,扩展一下:如果要改变设置,应该怎么办呢?我们通过相应的函数,先把这个结构体读出来,这与之前相同。不同的是,我们对结构体内的元素进行修改,最后,通过相应的函数,把修改后的结构体赋回去。也是比较容易理解的。

2. termios.h

加入了这个头文件,我们需要的函数就都包含在内了。

如读取设置:int tcgetattr(int fd, struct termios * info);

更新设置:int tcsetattr(int fd, int optional_actions, struct termios *termios_p);

获得波特率:int cfsetospeed(struct termios *termios_p, speed_t speed);

在上述参数中,我们发现了存储设置信息的结构体struct termios * info,它的定义如下:

[c]
struct termios
{
tcflag_t c_iflag;        /* input mode flags /
tcflag_t c_oflag;        /
output mode flags /
tcflag_t c_cflag;        /
control mode flags /
tcflag_t c_lflag;        /
local mode flags /
cc_t c_line;            /
line discipline /
cc_t c_cc[NCCS];        /
control characters /
speed_t c_ispeed;        /
input speed /
speed_t c_ospeed;        /
output speed */
#define _HAVE_STRUCT_TERMIOS_C_ISPEED 1
#define _HAVE_STRUCT_TERMIOS_C_OSPEED 1
};
[/c]

3. 位设置

c_iflag、c_oflag、c_cflag、c_lflag四个标志集的类型都是整型的。他们中的每一个都包含了许多项设置。这是怎么做到的呢?把一个整型变量按照二进制展开,就变成了一串“010101……”,就变成了一位一位的,而给每一位都赋予相应的设置,就相当于一串小开关,就可以控制多项设置了。同样c_cc[NCCS]数组也是如此,只是它不是用0、1控制每一位,而是用字符。

我以前学单片机编程的时候,这种方法应用广泛。

4.代码及注释

[c]

#include<stdio.h>
#include<termios.h>

main()
{
//termios结构体内储存着终端设置
struct termios ttyinfo;
//读取tty驱动程序属性
if( tcgetattr(0,&ttyinfo) == -1){
perror("cannot get params about stdin");
exit(1);
}
//显示波特率
/* cfgetospeed:
Return the output baud rate stored in *TERMIOS_P.  */
//而cfgetospeed返回的波特率值前面有个B(干什么的?)
//通过showbaud里的switch转为数值
showbaud( cfgetospeed(&ttyinfo));

//ttyinfo.c_cc数组里保存着控制字符
//每一位都有定义,如VERASE、VKILL
printf("The erase character is ascii %d, Ctrl-%cn",
ttyinfo.c_cc[VERASE],ttyinfo.c_cc[VERASE]-1+'a');
printf("The line kill character is ascii %d, Ctrl-%cn",
ttyinfo.c_cc[VKILL],ttyinfo.c_cc[VKILL]-1+'a');

//把input_flags和local_flags标志集的内容
//分别显示出来
show_some_flags(&ttyinfo);
}

showbaud(int thespeed)
{
printf("the baud rate is ");
switch( thespeed ){
case B300:    printf("300n");break;
case B600:    printf("600n");break;
case B1200:    printf("1200n");break;
case B2400:    printf("2400n");break;
case B4800:    printf("4800n");break;
case B9600:    printf("9600n");break;
default:    printf("Fastn");break;
}
}

//定义了一个结构体
//用于存储个标志集各位对应的说明
struct flaginfo{ int fl_value; char *fl_name};

//这是c_iflag的,敲地有点累啊= =
struct flaginfo input_flags[] ={
IGNBRK,        "Ignore break condition",
BRKINT,        "Signa interrupt on break",
IGNPAR,        "Ignore chars with parity errors",
PARMRK,        "Mark parity errors",
INPCK,        "Enable input parity check",
ISTRIP,        "Strip character",
INLCR,        "Map NL to CR on input",
IGNCR,        "Ignore CR",
ICRNL,        "Map CR to NL on input",
IXON,        "Enable start/stop output control",
IXOFF,        "Enable start/stop input control",
0,            NULL
};

//这是c_lflag的。。。= =
struct flaginfo local_flags[]={
ISIG,        "Enable signals",
ICANON,        "Canonical input (erase and kill)",
ECHO,        "Enable echo",
ECHOE,        "Echo ERASE as BS-SPACE-BS",
ECHOK,        "Echo KILL by starting new line",
0,            NULL
};

//把input_flags和local_flags标志集的内容
//分别显示出来
show_some_flags(struct termios * ttyp)
{
show_flagset(ttyp->c_iflag,input_flags);
show_flagset(ttyp->c_lflag,local_flags);
}

//显示一个标志集的设定
//标志集的是数值型的,因为它是按位来定义的
//input_flags[]和local_flags[]最末的两个0
//就是来控制for结束的
show_flagset(int thevalue, struct flaginfo thebitnames[])
{
int i;
for(i=0;thebitnames[i].fl_value;i++){
printf("%s is ", thebitnames[i].fl_name);
if(thevalue & thebitnames[i].fl_value)
printf("ONn");
else
printf("OFFn");

}
}

[/c]