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


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

    >./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

     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"
    ")
     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=":"
    12 while (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 }
    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
    ", flag); 
     7 #ifdef BRKINT
     8     if (flag & BRKINT)
     9         printf ("    BRKINT
    "); 
    10     else
    11         printf ("    BRKINT not in
    "); 
    12 #else
    13     printf ("    BRKINT not defined
    "); 
    14 #endif
    15 #ifdef ICRNL
    16     if (flag & ICRNL)
    17         printf ("    ICRNL
    "); 
    18     else
    19         printf ("    ICRNL not in
    "); 
    20 #else
    21     printf ("    ICRNL not defined
    "); 
    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 (CTRL+@)
        cc[VMIN=6] = 1 (CTRL+A)
        cc[VSWTC=7] = 255 (CTRL+?)
    

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

  • 相关阅读:
    Autofac官方文档翻译--二、解析服务--2隐式关系类型
    Verdi 不加载filelist,load design方法
    Power-Aware GateSim Debug
    simulation vs emulation
    关于SMI、MSI、SCI、INTx各种中断小结【转】
    zgrep用法
    sometimes we should use "disable fork" instead of "disable block_name"
    How to view assertions in the Verdi waveform viewer
    FIFO设计中的深度计算【zz】
    写写我的硕士三年【zz】
  • 原文地址:https://www.cnblogs.com/goodcitizen/p/widget_to_see_current_terminal_settings.html
Copyright © 2020-2023  润新知