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

>./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 结构体,我们可以获取一个终端设备的设置信息:

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

 #! /bin/awk -f
# usage: print_flag.awk -v FUNC_NAME=xxx -v MACRO_FILE=xxx
# i.e.: print_flag.awk -v FUNC_NAME=output -v MACRO_FILE=oflag.sym
BEGIN {
printf("#include \"../apue.h\"\n")
printf("#include <termios.h>\n")
printf("\n")
printf("void print_%s_flag (tcflag_t flag)\n", FUNC_NAME)
printf("{\n")
printf(" printf (\"%s flag 0x%%08x\\n\", flag); \n", FUNC_NAME)
FS=":"
while (getline < MACRO_FILE > ) {
printf("#ifdef %s\n", $)
printf(" if (flag & %s)\n", $)
printf(" printf (\" %s\\n\"); \n", $)
printf(" else\n")
printf(" printf (\" %s not in\\n\"); \n", $)
printf("#else\n")
printf(" printf (\" %s not defined\\n\"); \n", $)
printf("#endif\n")
}
close (MACRO_FILE)
exit
}
END {
printf("}")
}

生成的 c 文件类似这样:

 #include "../apue.h"
#include <termios.h> void print_input_flag (tcflag_t flag)
{
printf ("input flag 0x%08x\n", flag);
#ifdef BRKINT
if (flag & BRKINT)
printf (" BRKINT\n");
else
printf (" BRKINT not in\n");
#else
printf (" BRKINT not defined\n");
#endif
#ifdef ICRNL
if (flag & ICRNL)
printf (" ICRNL\n");
else
printf (" ICRNL not in\n");
#else
printf (" ICRNL not defined\n");
#endif
}

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

Makefile

 all: term 

 term: term.o print_iflag.o print_oflag.o print_cflag.o print_lflag.o print_cchar.o apue.o
gcc -Wall -g $^ -o $@ term.o: term.c ../apue.h
gcc -Wall -g -c $< -o $@ print_iflag.o: print_iflag.c ../apue.h
gcc -Wall -g -c $< -o $@ print_iflag.c: print_flag.awk iflag.sym
./print_flag.awk -v FUNC_NAME=input -v MACRO_FILE=iflag.sym > print_iflag.c print_oflag.o: print_oflag.c ../apue.h
gcc -Wall -g -c $< -o $@ print_oflag.c: print_flag.awk oflag.sym
./print_flag.awk -v FUNC_NAME=output -v MACRO_FILE=oflag.sym > print_oflag.c print_cflag.o: print_cflag.c ../apue.h
gcc -Wall -g -c $< -o $@ print_cflag.c: print_flag.awk cflag.sym
./print_flag.awk -v FUNC_NAME=control -v MACRO_FILE=cflag.sym > print_cflag.c print_lflag.o: print_lflag.c ../apue.h
gcc -Wall -g -c $< -o $@ print_lflag.c: print_flag.awk lflag.sym
./print_flag.awk -v FUNC_NAME=local -v MACRO_FILE=lflag.sym > print_lflag.c print_cchar.o: print_cchar.c ../apue.h
gcc -Wall -g -c $< -o $@ print_cchar.c: print_char.awk cchar.sym
./print_char.awk -v FUNC_NAME=control -v MACRO_FILE=cchar.sym > print_cchar.c log.o: ../log.c ../log.h
gcc -Wall -g -c $< -o $@ apue.o: ../apue.c ../apue.h
gcc -Wall -g -c $< -o $@ -D__USE_BSD clean:
@echo "start clean..."
-rm -f *.o core.* *.log *~ *.swp term
@echo "end clean" .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 (CTRL+@)
cc[VMIN=6] = 1 (CTRL+A)
cc[VSWTC=7] = 255 (CTRL+?)

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

后记

其实有一个现成的命令:stty,这个用来查看、修改终端设置,例如显示当前终端所有设置:

>stty -a
speed 38400 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?;
swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts -cdtrdsr
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke

不过这个命令是将所有配置打印出来,一不对它们进行分组、二不存在的标志也会显示出来(前面有个-),相比而言还是我们的工具更友好一些。

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

  1. 韩顺刚-tcp报文头协议详细分析第一包数据:序号是0,发送数据的长度是0,因为没有收到对端的数据,所以确认号是0, Syn的标志位设置成1,这里没有发送的数据,只发送TCP的20个字节的头部

    TCP报文段首部格式 大部分TCP报文头部都是20个字节,有的数据包要加上选项. 上面一行代表4个字节,源端口和目的端口都是2个字节. TCP协议是面向字节流的协议 TCP是一段一段分块的发送数据的 ...

  2. 分享一个 Linux 环境下,强力的Python 小工具

    场景 Linux 用户,经常需要在终端查看一些数据,从文件里看 或者网络协议获取数据并查看. 比如,查看文件里的json数据:比如,查看etcd里存下的数据. 如果直接看cat 或者 curl 得到的 ...

  3. [apue] 一个快速确定新系统上各类限制值的工具

    对于在不同 Unix 系统之间移植程序,最重要的事情就是确定新系统的一些编译时.运行时固定或不固定的限制值了.例如文件路径最大长度 PATH_MAX.进程最大可打开文件句柄数 OPEN_MAX.用户可 ...

  4. 进程保护--CrossThreadFlags标志位

    原理: 1. 将进程的所有线程的线程CrossThreadFlags标志位设置成Terminated或者System. 效果:任务管理器,WSYSCheck,ICESWORD无法结束进程.. 但PCH ...

  5. InkImageDataSetGenerator-开源一个可用于机器学习的书写轨迹图片生成的小工具

    这是一个简单易用的图片数据集生成小工具,基于OpenCV和UWP Ink API,它可以根据指定的手写轨迹生成一系列各个角度的图片.每张图片的尺寸和总体数量都是可以指定的,均存放在统一的生成目录中.h ...

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

    思考一个最简单的程序行为:我们的Dialog上有一个Button, 当用户用鼠标点击这个Button时, 我们弹出一个MessageBox.   这个看似简单的行为, 谁能说清楚它是如何运行起来的,背 ...

  7. C# 设置和获取一个字节的某一位的值的方法

    自己工作中遇到需要对单字节的高位.低位进行赋值,即一个字节byte,想要给每一位都赋值,这个值是动态来的,是0或是1. 好不容易收集到一些珍贵资料,整理一下: 一.设置 方法code: /// < ...

  8. 如何只修改EFLAGS寄存器中一个标志位的值?

    版权声明:本文为博主原创文章,2019-08-23,22:21:42转载请附上原文出处链接和本声明.作者By-----溺心与沉浮----博客园   1.写汇编指令只影响CF位的值(不能影响其他标志位 ...

  9. 登录操作(方法一:设置flag标志位)

    登录操作(方法一:设置flag标志位) user_name="star"passwoed='123'passed_authentication=Falsecount=0for i ...

随机推荐

  1. P1045 和为给定数

    题目描述 给出若干个整数,询问其中是否有一对数的和等于给定的数. 输入格式 共三行: 第一行是整数 \(n(0 \lt n \le 100000)\) ,表示有 \(n\) 个整数. 第二行是n个整数 ...

  2. ASP.NET Core 开启后台任务

    本文告诉大家如何通过 Microsoft.Extensions.Hosting.BackgroundService 开启后台任务 实现 BackManagerService 类继承 Backgroun ...

  3. 【58.75%】【BZOJ 1087】[SCOI2005]互不侵犯King

    Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 3040  Solved: 1786 [Submit][Status][Discuss] Descri ...

  4. 彻底弄懂slice和splice的区别

    总觉得数组和字符串中的一些方法的使用很难记,可能是日常都是在学理论,缺少实际应用.不多说了,继续学习吧! 一句话先提前概括: slice(start,end) 从哪到哪开始删 splice(strt, ...

  5. 牛客多校第三场 G Removing Stones(分治+线段树)

    牛客多校第三场 G Removing Stones(分治+线段树) 题意: 给你n个数,问你有多少个长度不小于2的连续子序列,使得其中最大元素不大于所有元素和的一半 题解: 分治+线段树 线段树维护最 ...

  6. 由“Sysnative”引发的思考

    在64位的Windows系统中,有个非常神秘的文件夹“Sysnative”,你无法通过Explorer去访问它,甚至你都无法找到它,但它却扮演了一个非常重要的角色.下面我们就来聊聊它. 32位和64位 ...

  7. 第二阶段:2.商业需求分析及BRD:2.产品需求池

    需求获取方式 比如公司战略方面的需求  用户的反馈:投诉 建议等等 产品经理需要时刻关注竞品以及行业的发展! 需求池:各个产品经理的需求总和成一个需求池.让资源更好的利用起来.有的公司还有个“需求管理 ...

  8. 别怕,"卷积"其实很简单(上)

    文章来自我的CSDN同名博客,欢迎文末扫码关注~   前言 相信很多时候,当我们在看到“卷积”时,总是处于一脸懵逼的状态,不但因为它的本身概念比较难理解,还因为它在不同的应用中发挥出的变幻莫测的作用也 ...

  9. (Go) 1. go环境配置

    第一步: 下载配置环境 转载: https://www.liwenzhou.com/posts/Go/go_menu/ 1.下载地址: https://golang.google.cn/dl/ 2.安 ...

  10. html页脚固定在底部的方法

    <style type="text/css"> html { height: 100%; } body { height: 100%; margin: 0; paddi ...