[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

4BEGIN {

5 printf("#include "../apue.h"

")

6 printf("#include <termios.h>

")

7 printf("

")

8 printf("void print_%s_flag (tcflag_t flag)

", FUNC_NAME)

9 printf("{

")

10 printf(" printf ("%s flag 0x%%08x\n", flag);

", FUNC_NAME)

11 FS=":"

12while (getline < MACRO_FILE > 0) {

13 printf("#ifdef %s

", $1)

14 printf(" if (flag & %s)

", $1)

15 printf(" printf (" %s\n");

", $1)

16 printf(" else

")

17 printf(" printf (" %s not in\n");

", $1)

18 printf("#else

")

19 printf(" printf (" %s not defined\n");

", $1)

20 printf("#endif

")

21}

22close (MACRO_FILE)

23exit

24}

25END {

26 printf("}")

27 }

 

生成的 c 文件类似这样:

 1 #include "../apue.h"

2 #include <termios.h>

3

4void print_input_flag (tcflag_t flag)

5{

6 printf ("input flag 0x%08x

", flag);

7#ifdef BRKINT

8if (flag & BRKINT)

9 printf (" BRKINT

");

10else

11 printf (" BRKINT not in

");

12#else

13 printf (" BRKINT not defined

");

14#endif

15#ifdef ICRNL

16if (flag & ICRNL)

17 printf (" ICRNL

");

18else

19 printf (" ICRNL not in

");

20#else

21 printf (" ICRNL not defined

");

22#endif

23 }

 

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

Makefile

 1all: term 

2

3term: term.o print_iflag.o print_oflag.o print_cflag.o print_lflag.o print_cchar.o apue.o

4gcc -Wall -g $^ -o $@

5

6 term.o: term.c ../apue.h

7gcc -Wall -g -c $< -o $@

8

9 print_iflag.o: print_iflag.c ../apue.h

10gcc -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

16gcc -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

22gcc -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

28gcc -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

34gcc -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

40gcc -Wall -g -c $< -o $@

41

42 apue.o: ../apue.c ../apue.h

43gcc -Wall -g -c $< -o $@ -D__USE_BSD

44

45clean:

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 ()

 

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

以上是 [apue]一个查看当前终端标志位设置的小工具 的全部内容, 来源链接: utcz.com/z/512944.html

回到顶部