[apue] 一個查看當前終端標誌位設置的小工具

話很少說,先看運行效果:linux

>./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 結構體,咱們能夠獲取一個終端設備的設置信息:ios

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 手冊。git

這個工具能夠將二進制的標誌位,翻譯爲人類能夠讀懂的常量宏,例如上面的輸出中,能夠看到輸入標誌位打開了 ICRNL 與 IXON 兩個標誌位,github

對應的含義分別是「將輸入的CR轉換爲NL」、「使啓動/中止輸出控制流起做用」。bash

 

看這段輸出也許你已經想到了代碼的實現,就是挨個常量宏嘗試唄,這有啥難的。工具

不錯,可是考慮到不一樣平臺上定義的宏不一致,有時增長一兩個宏可能還須要修改源代碼,這是多麼痛苦的事啊!測試

這個小工具就解決了這個痛點,你能夠在配置文件中指定要測試的宏名稱,而後 make 一下就能夠啦~~~spa

 

iflag.sym翻譯

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

 

oflag.symcode

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 $@
 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

VTIME
VMIN
VSWTC

 

將它們添加到 sym 文件中,從新編譯、運行,果真新的輸出裏有了:

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

 

這對於在不一樣平臺上進行測試有很大的幫助。

相關文章
相關標籤/搜索