前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[apue] 一个查看当前终端标志位设置的小工具

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

作者头像
海海
发布2022-08-19 10:25:34
5380
发布2022-08-19 10:25:34
举报
文章被收录于专栏:goodcitizen

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

代码语言:javascript
复制
>./term
input flag 0x00006d02
    BRKINT
    ICRNL
    IMAXBEL
    IXANY
    IXON
output flag 0x00000005
    ONLCR
    OPOST
control flag 0x000004bf
    CREAD
    CSIZE
    CS6
    CS7
    CS8
    HUPCL
local flag 0x00008a3b
    ECHO
    ECHOE
    ECHOK
    ICANON
    IEXTEN
    ISIG
input control char array size 32
    cc[VDISCARD=13] = 15 (CTRL+O)
    VDSUSP not defined
    cc[VEOF=4] = 4 (CTRL+D)
    cc[VEOL=11] = 255 (CTRL+?)
    cc[VEOL2=16] = 255 (CTRL+?)
    cc[VERASE=2] = 127 (CTRL+�)
    VERASE2 not defined
    cc[VINTR=0] = 3 (CTRL+C)
    cc[VKILL=3] = 21 (CTRL+U)
    cc[VLNEXT=15] = 22 (CTRL+V)
    cc[VQUIT=1] = 28 (CTRL+\)
    cc[VREPRINT=12] = 18 (CTRL+R)
    cc[VSTART=8] = 17 (CTRL+Q)
    VSTATUS not defined
    cc[VSTOP=9] = 19 (CTRL+S)
    cc[VSUSP=10] = 26 (CTRL+Z)
    cc[VWERASE=14] = 23 (CTRL+W)

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

代码语言:javascript
复制
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

代码语言:javascript
复制
BRKINT
ICRNL
IGNBRK
IGNCR
IGNPAR
IMAXBEL
INLCR
INPCK
ISTRIP
IUCLC
IXANY
IXOFF
IXON
PARMRK

oflag.sym

代码语言:javascript
复制
BSDLY
CMSPAR
CRDLY
FFDLY
NLDLY
OCRNL
OFDEL
OFILL
OLCUC
ONLCR
ONLRET
ONOCR
ONOEOT
OPOST
OXTABS
TABDLY
VTDLY

cflag.sym

代码语言:javascript
复制
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

代码语言:javascript
复制
ALTWERASE
ECHO
ECHOCTL
ECHOE
ECHOK
ECHOKE
ECHONL
ECHOPRT
EXTPROC
FLUSHO
ICANON
IEXTEN
ISIG
NOFLSH
NOKERNINFO
PENDIN
TOSTOP
XCASE

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

print_flag.awk

代码语言:javascript
复制
 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 文件类似这样:

代码语言:javascript
复制
 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

代码语言:javascript
复制
 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 $@
 5 
 6 term.o: term.c ../apue.h
 7     gcc -Wall -g -c $< -o $@
 8 
 9 print_iflag.o: print_iflag.c ../apue.h
10     gcc -Wall -g -c $< -o $@
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 $@
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 $@
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 $@
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 $@
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 $@
41 
42 apue.o: ../apue.c ../apue.h 
43     gcc -Wall -g -c $< -o $@ -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

代码语言:javascript
复制
VTIME
VMIN
VSWTC

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

代码语言:javascript
复制
    cc[VTIME=5] = 0 (CTRL+@)
    cc[VMIN=6] = 1 (CTRL+A)
    cc[VSWTC=7] = 255 (CTRL+?)

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-01-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档