[apue] 一个查看当前终端标志位设置的小工具

话不多说,先看运行效果:

>./term
input flag 0x00000500
    BRKINT not in
    ICRNL
    IGNBRK not in
    IGNCR not in
    IGNPAR not in
    IMAXBEL not in
    INLCR not in
    INPCK not in
    ISTRIP not in
    IUCLC not in
    IXANY not in
    IXOFF not in
    IXON
    PARMRK not in
output flag 0x00000005
    BSDLY not in
    CMSPAR not defined
    CRDLY not in
    FFDLY not in
    NLDLY not in
    OCRNL not in
    OFDEL not in
    OFILL not in
    OLCUC not in
    ONLCR
    ONLRET not in
    ONOCR not in
    ONOEOT not defined
    OPOST
    OXTABS not defined
    TABDLY not in
    VTDLY not in
control flag 0x000000bf
    CBAUDEXT not defined
    CCAR_OFLOW not defined
    CCTS_OFLOW not defined
    CDSR_OFLOW not defined
    CDTR_IFLOW not defined
    CIBAUDEXT not defined
    CIGNORE not defined
    CLOCAL not in
    CREAD
    CRTSCTS not defined
    CRTS_IFLOW not defined
    CRTSXOFF not defined
    CSIZE
    CSTOPB not in
    HUPCL not in
    MDMBUF not defined
    PARENB not in
    PAREXT not defined
    PARODD not in
local flag 0x00008a3b
    ALTWERASE not defined
    ECHO
    ECHOCTL not defined
    ECHOE
    ECHOK
    ECHOKE not defined
    ECHONL not in
    ECHOPRT not defined
    EXTPROC not defined
    FLUSHO not defined
    ICANON
    IEXTEN
    ISIG
    NOFLSH not in
    NOKERNINFO not defined
    PENDIN not defined
    TOSTOP not in
    XCASE not in
input control char array size 32
    cc[VDISCARD=13] = 15 ()
    VDSUSP not defined
    cc[VEOF=4] = 4 ()
    cc[VEOL=11] = 0 ()
    cc[VEOL2=16] = 0 ()
    cc[VERASE=2] = 127 ()
    VERASE2 not defined
    cc[VINTR=0] = 3 ()
    cc[VKILL=3] = 21 ()
    cc[VLNEXT=15] = 22 ()
    cc[VQUIT=1] = 28 ()
    cc[VREPRINT=12] = 18 ()
    cc[VSTART=8] = 17 ()
    VSTATUS not defined
    cc[VSTOP=9] = 19 ()
    cc[VSUSP=10] = 26 ()
    cc[VWERASE=14] = 23 ()

众所周知,通过 tcgetattr 接口与 termios 结构体,我们可以获取一个终端设备的设置信息:

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_cc[NCCS];        /* control characters */
};

主要是各种类型的标志位,虽然你可以将它们打印出来,但是一眼望去,这些数字是什么意思,还要查对应平台的 man 手册。

这个工具可以将二进制的标志位,翻译为人类可以读懂的常量宏,例如上面的输出中,可以看到输入标志位打开了 ICRNL 与 IXON 两个标志位,

对应的含义分别是“将输入的CR转换为NL”、“使启动/停止输出控制流起作用”。

看这段输出也许你已经想到了代码的实现,就是挨个常量宏尝试呗,这有啥难的。

不错,但是考虑到不同平台上定义的宏不一致,有时增加一两个宏可能还需要修改源代码,这是多么痛苦的事啊!

这个小工具就解决了这个痛点,你可以在配置文件中指定要测试的宏名称,然后 make 一下就可以啦~~~

iflag.sym

BRKINT
ICRNL
IGNBRK
IGNCR
IGNPAR
IMAXBEL
INLCR
INPCK
ISTRIP
IUCLC
IXANY
IXOFF
IXON
PARMRK

oflag.sym

BSDLY
CMSPAR
CRDLY
FFDLY
NLDLY
OCRNL
OFDEL
OFILL
OLCUC
ONLCR
ONLRET
ONOCR
ONOEOT
OPOST
OXTABS
TABDLY
VTDLY

cflag.sym

CBAUDEXT
CCAR_OFLOW
CCTS_OFLOW
CDSR_OFLOW
CDTR_IFLOW
CIBAUDEXT
CIGNORE
CLOCAL
CREAD
CRTSCTS
CRTS_IFLOW
CRTSXOFF
CSIZE
CSTOPB
HUPCL
MDMBUF
PARENB
PAREXT
PARODD

lflag.sym

ALTWERASE
ECHO
ECHOCTL
ECHOE
ECHOK
ECHOKE
ECHONL
ECHOPRT
EXTPROC
FLUSHO
ICANON
IEXTEN
ISIG
NOFLSH
NOKERNINFO
PENDIN
TOSTOP
XCASE

其实这里是用 awk 读取配置文件自动生成 c 语言的代码来实现的:

print_flag.awk

 1 #! /bin/awk -f
 2 # usage: print_flag.awk -v FUNC_NAME=xxx -v MACRO_FILE=xxx
 3 # i.e.: print_flag.awk -v FUNC_NAME=output -v MACRO_FILE=oflag.sym
 4 BEGIN {
 5 printf("#include \"../apue.h\"\n")
 6 printf("#include <termios.h>\n")
 7 printf("\n")
 8 printf("void print_%s_flag (tcflag_t flag)\n", FUNC_NAME)
 9 printf("{\n")
10 printf("    printf (\"%s flag 0x%%08x\\n\", flag); \n", FUNC_NAME)
11 FS=":"
12 while (getline < MACRO_FILE > 0) {
13 printf("#ifdef %s\n", $1)
14 printf("    if (flag & %s)\n", $1)
15 printf("        printf (\"    %s\\n\"); \n", $1)
16 printf("    else\n")
17 printf("        printf (\"    %s not in\\n\"); \n", $1)
18 printf("#else\n")
19 printf("    printf (\"    %s not defined\\n\"); \n", $1)
20 printf("#endif\n")
21 }
22 close (MACRO_FILE)
23 exit
24 }
25 END {
26 printf("}")
27 }

生成的 c 文件类似这样:

 1 #include "../apue.h"
 2 #include <termios.h>
 3
 4 void print_input_flag (tcflag_t flag)
 5 {
 6     printf ("input flag 0x%08x\n", flag);
 7 #ifdef BRKINT
 8     if (flag & BRKINT)
 9         printf ("    BRKINT\n");
10     else
11         printf ("    BRKINT not in\n");
12 #else
13     printf ("    BRKINT not defined\n");
14 #endif
15 #ifdef ICRNL
16     if (flag & ICRNL)
17         printf ("    ICRNL\n");
18     else
19         printf ("    ICRNL not in\n");
20 #else
21     printf ("    ICRNL not defined\n");
22 #endif
23 }

再看下 Makefile 的生成规则就更清楚啦:

Makefile

 1 all: term
 2
 3 term: term.o print_iflag.o print_oflag.o print_cflag.o print_lflag.o print_cchar.o apue.o
 4     gcc -Wall -g $^ -o [email protected]
 5
 6 term.o: term.c ../apue.h
 7     gcc -Wall -g -c $< -o [email protected]
 8
 9 print_iflag.o: print_iflag.c ../apue.h
10     gcc -Wall -g -c $< -o [email protected]
11
12 print_iflag.c: print_flag.awk iflag.sym
13     ./print_flag.awk -v FUNC_NAME=input -v MACRO_FILE=iflag.sym > print_iflag.c
14
15 print_oflag.o: print_oflag.c ../apue.h
16     gcc -Wall -g -c $< -o [email protected]
17
18 print_oflag.c: print_flag.awk oflag.sym
19     ./print_flag.awk -v FUNC_NAME=output -v MACRO_FILE=oflag.sym > print_oflag.c
20
21 print_cflag.o: print_cflag.c ../apue.h
22     gcc -Wall -g -c $< -o [email protected]
23
24 print_cflag.c: print_flag.awk cflag.sym
25     ./print_flag.awk -v FUNC_NAME=control -v MACRO_FILE=cflag.sym > print_cflag.c
26
27 print_lflag.o: print_lflag.c ../apue.h
28     gcc -Wall -g -c $< -o [email protected]
29
30 print_lflag.c: print_flag.awk lflag.sym
31     ./print_flag.awk -v FUNC_NAME=local -v MACRO_FILE=lflag.sym > print_lflag.c
32
33 print_cchar.o: print_cchar.c ../apue.h
34     gcc -Wall -g -c $< -o [email protected]
35
36 print_cchar.c: print_char.awk cchar.sym
37     ./print_char.awk -v FUNC_NAME=control -v MACRO_FILE=cchar.sym > print_cchar.c
38
39 log.o: ../log.c ../log.h
40     gcc -Wall -g -c $< -o [email protected]
41
42 apue.o: ../apue.c ../apue.h
43     gcc -Wall -g -c $< -o [email protected] -D__USE_BSD
44
45 clean:
46     @echo "start clean..."
47     -rm -f *.o core.* *.log *~ *.swp term
48     @echo "end clean"
49
50 .PHONY: clean

具体分析下生成过程:

1.通过 print_flag.awk 分别生成 print_iflag.c / print_oflag.c / print_cflag.c / print_lflag.c

2.分别将生成的 .c 编译为 .o 文件

3.在生成 term 工具时链接上述 .o 文件生成最终的可执行文件

当然了,除了各种标志位外,这里还处理了 cc_t cc 字段,它打印每个特殊输入字符,原理和上面相仿,就不再赘述了。

检查打印的特殊字符,发现少了下标为 5 / 6 / 7 的字符,查看头文件定义,原来是 linux 上面增加了三个新的定义:

cchar.sym

VTIME
VMIN
VSWTC

将它们添加到 sym 文件中,重新编译、运行,果然新的输出里有了:

    cc[VTIME=5] = 0 ()
    cc[VMIN=6] = 1 ()
    cc[VSWTC=7] = 0 ()

这对于在不同平台上进行测试有很大的帮助。

原文地址:https://www.cnblogs.com/goodcitizen/p/12222417.html

时间: 2024-10-28 23:42:22

[apue] 一个查看当前终端标志位设置的小工具的相关文章

一个用来提取网页中图片的小工具

public Array MatchHtml(string html,string com) { List<string> urls = new List<string>(); html = html.ToLower(); //获取SRC标签中的URL Regex regexSrc = new Regex("src=\"[^\"]*[(.jpg)(.png)(.gif)(.bmp)(.ico)]\""); foreach(Match

一个练习日语五十音图的小工具

<html> <head> <title>五十音练习</title> <style type="text/css"> label { font-size:50px; font-face:微软雅黑; } </style> <script type="text/javascript"> var element = ["あ","い","う&

进程保护--CrossThreadFlags标志位

原理: 1. 将进程的所有线程的线程CrossThreadFlags标志位设置成Terminated或者System. 效果:任务管理器,WSYSCheck,ICESWORD无法结束进程.. 但PCHunter 可以结束受保护的进程.但PCHunter无法用普通方法结束受保护的线程,必须使用强制结束线程才可结束线程.. 代码: VOID SetThreadFlagToTerminatedByThreadID(ULONG dwThreadID) { ULONG ulFlagOffset; NTST

从点击Button到弹出一个MessageBox, 背后发生了什么(每个UI线程都有一个ThreadInfo结构, 里面包含4个队列和一些标志位)

思考一个最简单的程序行为:我们的Dialog上有一个Button, 当用户用鼠标点击这个Button时, 我们弹出一个MessageBox. 这个看似简单的行为, 谁能说清楚它是如何运行起来的,背后究竟发生了什么? 下面是我个人尝试的解答: (1)我们的鼠标点击事件到达设备的驱动程序, 驱动程序把消息放入系统硬件输入队列SHIQ(system hardware input queue). (2)通过系统的原始输入线程 RIT (raw input thread)把鼠标事件发送到对应的窗口.这里我

TCP协议中的标志位

TCP/IP协议通常放在一起来说,但是它们是两个不同的协议,所起的作用也不一样. IP协议是用来查找地址的,对应于网际互联层. TCP协议是用来规范传输规则的,对应着传输层. IP协议只负责找到地址,具体传输的工作交给TCP来完成. TCP在传输之前会进行三次沟通,一般称为“三握手”:传输数据断开的时候需要进行四次沟通,一般称为“四挥手”. 要理解这个过程首先需要理解TCP中的两个序号和三个标志位的含义: seq:sequence number的缩写,表示所传数据的序号.TCP传输时每一个字节都

3.汇编中的标志位

这周主要学习的是转移指令的相关知识和原理. offset在和汇编语言中是由编译器处理的符号,它的功能是取得标号的偏移地址. jmp是无条件转移指令,可以只修改IP,也可以同时修改CS和IP. CPU在执行jmp指令的时候不需要转移的目的地址,机器码中包含的的是转移的位移. Ret指令用栈中的数据,修改IP的内容,从而实现近转移. Ret=POP  IP Retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移. Retf=POP IP     POP CS   CPU执行call指令时,进

转发的别人的vim编码和终端编码的设置

VIM中字符编码的设置             2008-07-24 12:54:18 分类: VIM中,我们可以通过修改/etc/vimrc文件来设置VIM的encoding,我们可以通过:help encoding来察看vim中关于encoding的一些帮助,:help encoding-values可以看到vim支持的encoding的值. vim的encoding设置通常有三个参数: 1.encoding     表示vim自身内部使用的编码方式,如内部缓冲,菜单,消息等的编码方式.如果

常用汇编指令及其影响的标志位

加法指令 ADD (addition) 指令对标志位的影响: CF=1   最高有效位向高位有进位 CF=0   最高有效位向高位无进位 OF=1   两个同符号数相加(正数+正数 或 负数+负数),结果符号与其相反. OF=0   两个不同符号数相加,或同符号数相加,结果符号与其相同. 带进位加法指令 ADC (add with carry) 指令对标志位的影响: CF=1   最高有效位向高位有进位 CF=0   最低有效位相高位无进位 OF=1   两个同符号数相加,结果符号与其相反, O

嵌入式单片机,外部中断,中断标志位介绍

body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;} th{border: 1px solid gray; padding: 4px; background-color: #DDD;} td{border: 1px solid gray; padding: 4px;} tr:nth-chil