#!/usr/bin/env python """ Display known information about our terminal. """ from __future__ import print_function import termios import locale import sys import os BITMAP_IFLAG = { 'IGNBRK': 'ignore BREAK condition', 'BRKINT': 'map BREAK to SIGINTR', 'IGNPAR': 'ignore (discard) parity errors', 'PARMRK': 'mark parity and framing errors', 'INPCK': 'enable checking of parity errors', 'ISTRIP': 'strip 8th bit off chars', 'INLCR': 'map NL into CR', 'IGNCR': 'ignore CR', 'ICRNL': 'map CR to NL (ala CRMOD)', 'IXON': 'enable output flow control', 'IXOFF': 'enable input flow control', 'IXANY': 'any char will restart after stop', 'IMAXBEL': 'ring bell on input queue full', 'IUCLC': 'translate upper case to lower case', } BITMAP_OFLAG = { 'OPOST': 'enable following output processing', 'ONLCR': 'map NL to CR-NL (ala CRMOD)', 'OXTABS': 'expand tabs to spaces', 'ONOEOT': 'discard EOT\'s `^D\' on output)', 'OCRNL': 'map CR to NL', 'OLCUC': 'translate lower case to upper case', 'ONOCR': 'No CR output at column 0', 'ONLRET': 'NL performs CR function', } BITMAP_CFLAG = { 'CSIZE': 'character size mask', 'CS5': '5 bits (pseudo)', 'CS6': '6 bits', 'CS7': '7 bits', 'CS8': '8 bits', 'CSTOPB': 'send 2 stop bits', 'CREAD': 'enable receiver', 'PARENB': 'parity enable', 'PARODD': 'odd parity, else even', 'HUPCL': 'hang up on last close', 'CLOCAL': 'ignore modem status lines', 'CCTS_OFLOW': 'CTS flow control of output', 'CRTSCTS': 'same as CCTS_OFLOW', 'CRTS_IFLOW': 'RTS flow control of input', 'MDMBUF': 'flow control output via Carrier', } BITMAP_LFLAG = { 'ECHOKE': 'visual erase for line kill', 'ECHOE': 'visually erase chars', 'ECHO': 'enable echoing', 'ECHONL': 'echo NL even if ECHO is off', 'ECHOPRT': 'visual erase mode for hardcopy', 'ECHOCTL': 'echo control chars as ^(Char)', 'ISIG': 'enable signals INTR, QUIT, [D]SUSP', 'ICANON': 'canonicalize input lines', 'ALTWERASE': 'use alternate WERASE algorithm', 'IEXTEN': 'enable DISCARD and LNEXT', 'EXTPROC': 'external processing', 'TOSTOP': 'stop background jobs from output', 'FLUSHO': 'output being flushed (state)', 'NOKERNINFO': 'no kernel output from VSTATUS', 'PENDIN': 'XXX retype pending input (state)', 'NOFLSH': 'don\'t flush after interrupt', } CTLCHAR_INDEX = { 'VEOF': 'EOF', 'VEOL': 'EOL', 'VEOL2': 'EOL2', 'VERASE': 'ERASE', 'VWERASE': 'WERASE', 'VKILL': 'KILL', 'VREPRINT': 'REPRINT', 'VINTR': 'INTR', 'VQUIT': 'QUIT', 'VSUSP': 'SUSP', 'VDSUSP': 'DSUSP', 'VSTART': 'START', 'VSTOP': 'STOP', 'VLNEXT': 'LNEXT', 'VDISCARD': 'DISCARD', 'VMIN': '---', 'VTIME': '---', 'VSTATUS': 'STATUS', } def display_bitmask(kind, bitmap, value): """ Display all matching bitmask values for ``value`` given ``bitmap``. """ col1_width = max(map(len, list(bitmap.keys()) + [kind])) col2_width = 7 FMT = '{name:>{col1_width}} {value:>{col2_width}} {description}' print(FMT.format(name=kind, value='Value', description='Description', col1_width=col1_width, col2_width=col2_width)) print('{0} {1} {2}'.format('-' * col1_width, '-' * col2_width, '-' * max(map(len, bitmap.values())))) for flag_name, description in bitmap.items(): try: bitmask = getattr(termios, flag_name) bit_val = 'on' if bool(value & bitmask) else 'off' except AttributeError: bit_val = 'undef' print(FMT.format(name=flag_name, value=bit_val, description=description, col1_width=col1_width, col2_width=col2_width)) print() def display_ctl_chars(index, cc): """ Display all control character indicies, names, and values. """ title = 'Special Character' col1_width = len(title) col2_width = max(map(len, index.values())) FMT = '{idx:<{col1_width}} {name:<{col2_width}} {value}' print('Special line Characters'.center(40).rstrip()) print(FMT.format(idx='Index', name='Name', value='Value', col1_width=col1_width, col2_width=col2_width)) print('{0} {1} {2}'.format('-' * col1_width, '-' * col2_width, '-' * 10)) for index_name, name in index.items(): try: index = getattr(termios, index_name) value = cc[index] if value == b'\xff': value = '_POSIX_VDISABLE' else: value = repr(value) except AttributeError: value = 'undef' print(FMT.format(idx=index_name, name=name, value=value, col1_width=col1_width, col2_width=col2_width)) print() def display_conf(kind, names, getter): col1_width = max(map(len, names)) FMT = '{name:>{col1_width}} {value}' print(FMT.format(name=kind, value='value', col1_width=col1_width)) print('{0} {1}'.format('-' * col1_width, '-' * 27)) for name in names: try: value = getter(name) except OSError as err: value = err print(FMT.format(name=name, value=value, col1_width=col1_width)) print() def main(): fd = sys.stdin.fileno() locale.setlocale(locale.LC_ALL, '') encoding = locale.getpreferredencoding() print('os.isatty({0}) => {1}'.format(fd, os.isatty(fd))) print('locale.getpreferredencoding() => {0}'.format(encoding)) display_conf(kind='pathconf', names=os.pathconf_names, getter=lambda name: os.fpathconf(fd, name)) try: (iflag, oflag, cflag, lflag, ispeed, ospeed, cc ) = termios.tcgetattr(fd) except termios.error as err: print('stdin is not a typewriter: {0}'.format(err)) else: display_bitmask(kind='Input Mode', bitmap=BITMAP_IFLAG, value=iflag) display_bitmask(kind='Output Mode', bitmap=BITMAP_OFLAG, value=oflag) display_bitmask(kind='Control Mode', bitmap=BITMAP_CFLAG, value=cflag) display_bitmask(kind='Local Mode', bitmap=BITMAP_LFLAG, value=lflag) display_ctl_chars(index=CTLCHAR_INDEX, cc=cc) try: print('os.ttyname({0}) => {1}'.format(fd, os.ttyname(fd))) print('os.ctermid() => {0}'.format(os.ctermid())) except OSError as e: # Travis fails on ttyname with errno 0 'Error'. print("Error inspecting TTY: {0}".format(e)) if __name__ == '__main__': main()