static tcflag_t *get_ptr_to_tcflag(unsigned type, const struct termios *mode) { static const uint8_t tcflag_offsets[] ALIGN1 = { offsetof(struct termios, c_cflag), /* control */ offsetof(struct termios, c_iflag), /* input */ offsetof(struct termios, c_oflag), /* output */ offsetof(struct termios, c_lflag) /* local */ }; if (type <= local) { return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]); } return NULL; } /* Flags for 'struct mode_info' */ #define SANE_SET 1 /* Set in 'sane' mode */ #define SANE_UNSET 2 /* Unset in 'sane' mode */ #define REV 4 /* Can be turned off by prepending '-' */ #define OMIT 8 /* Don't display value */ /* Each mode. * This structure should be kept as small as humanly possible. */ struct mode_info { const uint8_t type; /* Which structure element to change */ const uint8_t flags; /* Setting and display options */ /* only these values are ever used, so... */ #if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100 const uint8_t mask; #elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000 const uint16_t mask; #else const tcflag_t mask; /* Other bits to turn off for this mode */ #endif /* was using short here, but ppc32 was unhappy */ const tcflag_t bits; /* Bits to set for this mode */ }; enum { /* Must match mode_name[] and mode_info[] order! */ IDX_evenp = 0, IDX_parity, IDX_oddp, IDX_nl, IDX_ek, IDX_sane, IDX_cooked, IDX_raw, IDX_pass8, IDX_litout, IDX_cbreak, IDX_crt, IDX_dec, #if IXANY IDX_decctlq, #endif #if TABDLY || OXTABS IDX_tabs, #endif #if XCASE && IUCLC && OLCUC IDX_lcase, IDX_LCASE, #endif }; #define MI_ENTRY(N,T,F,B,M) N "\0" /* Mode names given on command line */ static const char mode_name[] = MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) MI_ENTRY("ek", combination, OMIT, 0, 0 ) MI_ENTRY("sane", combination, OMIT, 0, 0 ) MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) MI_ENTRY("crt", combination, OMIT, 0, 0 ) MI_ENTRY("dec", combination, OMIT, 0, 0 ) #if IXANY MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) #endif #if TABDLY || OXTABS MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) #endif #if XCASE && IUCLC && OLCUC MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) #endif MI_ENTRY("parenb", control, REV, PARENB, 0 ) MI_ENTRY("parodd", control, REV, PARODD, 0 ) MI_ENTRY("cs5", control, 0, CS5, CSIZE) MI_ENTRY("cs6", control, 0, CS6, CSIZE) MI_ENTRY("cs7", control, 0, CS7, CSIZE) MI_ENTRY("cs8", control, 0, CS8, CSIZE) MI_ENTRY("hupcl", control, REV, HUPCL, 0 ) MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ) MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) #if CRTSCTS MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) #endif MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ) MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ) MI_ENTRY("parmrk", input, REV, PARMRK, 0 ) MI_ENTRY("inpck", input, REV, INPCK, 0 ) MI_ENTRY("istrip", input, REV, ISTRIP, 0 ) MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ) MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ) MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ) MI_ENTRY("ixon", input, REV, IXON, 0 ) MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) #if IUCLC MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) #endif #if IXANY MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) #endif #if IMAXBEL MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) #endif #if IUTF8 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 ) #endif MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) #if OLCUC MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) #endif #if OCRNL MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) #endif #if ONLCR MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) #endif #if ONOCR MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) #endif #if ONLRET MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) #endif #if OFILL MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) #endif #if OFDEL MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) #endif #if NLDLY MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) #endif #if CRDLY MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY) MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY) MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY) MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY) #endif #if TABDLY MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY) # if TAB2 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY) # endif # if TAB1 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY) # endif MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY) #else # if OXTABS MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) # endif #endif #if BSDLY MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) #endif #if VTDLY MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) #endif #if FFDLY MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY) MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY) #endif MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ) MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ) #if IEXTEN MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) #endif MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) #if XCASE MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) #endif #if TOSTOP MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) #endif #if ECHOPRT MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) #endif #if ECHOCTL MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) #endif #if ECHOKE MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) #endif ; #undef MI_ENTRY #define MI_ENTRY(N,T,F,B,M) { T, F, M, B }, static const struct mode_info mode_info[] = { /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */ MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) MI_ENTRY("ek", combination, OMIT, 0, 0 ) MI_ENTRY("sane", combination, OMIT, 0, 0 ) MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) MI_ENTRY("crt", combination, OMIT, 0, 0 ) MI_ENTRY("dec", combination, OMIT, 0, 0 ) #if IXANY MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) #endif #if TABDLY || OXTABS MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) #endif #if XCASE && IUCLC && OLCUC MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) #endif MI_ENTRY("parenb", control, REV, PARENB, 0 ) MI_ENTRY("parodd", control, REV, PARODD, 0 ) MI_ENTRY("cs5", control, 0, CS5, CSIZE) MI_ENTRY("cs6", control, 0, CS6, CSIZE) MI_ENTRY("cs7", control, 0, CS7, CSIZE) MI_ENTRY("cs8", control, 0, CS8, CSIZE) MI_ENTRY("hupcl", control, REV, HUPCL, 0 ) MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ) MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) #if CRTSCTS MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) #endif MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ) MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ) MI_ENTRY("parmrk", input, REV, PARMRK, 0 ) MI_ENTRY("inpck", input, REV, INPCK, 0 ) MI_ENTRY("istrip", input, REV, ISTRIP, 0 ) MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ) MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ) MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ) MI_ENTRY("ixon", input, REV, IXON, 0 ) MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) #if IUCLC MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) #endif #if IXANY MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) #endif #if IMAXBEL MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) #endif #if IUTF8 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 ) #endif MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) #if OLCUC MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) #endif #if OCRNL MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) #endif #if ONLCR MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) #endif #if ONOCR MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) #endif #if ONLRET MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) #endif #if OFILL MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) #endif #if OFDEL MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) #endif #if NLDLY MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) #endif #if CRDLY MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY) MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY) MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY) MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY) #endif #if TABDLY MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY) # if TAB2 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY) # endif # if TAB1 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY) # endif MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY) #else # if OXTABS MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) # endif #endif #if BSDLY MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) #endif #if VTDLY MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) #endif #if FFDLY MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY) MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY) #endif MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ) MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ) #if IEXTEN MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) #endif MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) #if XCASE MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) #endif #if TOSTOP MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) #endif #if ECHOPRT MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) #endif #if ECHOCTL MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) #endif #if ECHOKE MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) #endif }; enum { NUM_mode_info = ARRAY_SIZE(mode_info) }; /* Control characters */ struct control_info { const uint8_t saneval; /* Value to set for 'stty sane' */ const uint8_t offset; /* Offset in c_cc */ }; enum { /* Must match control_name[] and control_info[] order! */ CIDX_intr = 0, CIDX_quit, CIDX_erase, CIDX_kill, CIDX_eof, CIDX_eol, #if VEOL2 CIDX_eol2, #endif #if VSWTCH CIDX_swtch, #endif CIDX_start, CIDX_stop, CIDX_susp, #if VDSUSP CIDX_dsusp, #endif #if VREPRINT CIDX_rprnt, #endif #if VWERASE CIDX_werase, #endif #if VLNEXT CIDX_lnext, #endif #if VFLUSHO CIDX_flush, #endif #if VSTATUS CIDX_status, #endif CIDX_min, CIDX_time, }; #define CI_ENTRY(n,s,o) n "\0" /* Name given on command line */ static const char control_name[] = CI_ENTRY("intr", CINTR, VINTR ) CI_ENTRY("quit", CQUIT, VQUIT ) CI_ENTRY("erase", CERASE, VERASE ) CI_ENTRY("kill", CKILL, VKILL ) CI_ENTRY("eof", CEOF, VEOF ) CI_ENTRY("eol", CEOL, VEOL ) #if VEOL2 CI_ENTRY("eol2", CEOL2, VEOL2 ) #endif #if VSWTCH CI_ENTRY("swtch", CSWTCH, VSWTCH ) #endif CI_ENTRY("start", CSTART, VSTART ) CI_ENTRY("stop", CSTOP, VSTOP ) CI_ENTRY("susp", CSUSP, VSUSP ) #if VDSUSP CI_ENTRY("dsusp", CDSUSP, VDSUSP ) #endif #if VREPRINT CI_ENTRY("rprnt", CRPRNT, VREPRINT) #endif #if VWERASE CI_ENTRY("werase", CWERASE, VWERASE ) #endif #if VLNEXT CI_ENTRY("lnext", CLNEXT, VLNEXT ) #endif #if VFLUSHO CI_ENTRY("flush", CFLUSHO, VFLUSHO ) #endif #if VSTATUS CI_ENTRY("status", CSTATUS, VSTATUS ) #endif /* These must be last because of the display routines */ CI_ENTRY("min", 1, VMIN ) CI_ENTRY("time", 0, VTIME ) ; #undef CI_ENTRY #define CI_ENTRY(n,s,o) { s, o }, static const struct control_info control_info[] = { /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */ CI_ENTRY("intr", CINTR, VINTR ) CI_ENTRY("quit", CQUIT, VQUIT ) CI_ENTRY("erase", CERASE, VERASE ) CI_ENTRY("kill", CKILL, VKILL ) CI_ENTRY("eof", CEOF, VEOF ) CI_ENTRY("eol", CEOL, VEOL ) #if VEOL2 CI_ENTRY("eol2", CEOL2, VEOL2 ) #endif #if VSWTCH CI_ENTRY("swtch", CSWTCH, VSWTCH ) #endif CI_ENTRY("start", CSTART, VSTART ) CI_ENTRY("stop", CSTOP, VSTOP ) CI_ENTRY("susp", CSUSP, VSUSP ) #if VDSUSP CI_ENTRY("dsusp", CDSUSP, VDSUSP ) #endif #if VREPRINT CI_ENTRY("rprnt", CRPRNT, VREPRINT) #endif #if VWERASE CI_ENTRY("werase", CWERASE, VWERASE ) #endif #if VLNEXT CI_ENTRY("lnext", CLNEXT, VLNEXT ) #endif #if VFLUSHO CI_ENTRY("flush", CFLUSHO, VFLUSHO ) #endif #if VSTATUS CI_ENTRY("status", CSTATUS, VSTATUS ) #endif /* These must be last because of the display routines */ CI_ENTRY("min", 1, VMIN ) CI_ENTRY("time", 0, VTIME ) }; enum { NUM_control_info = ARRAY_SIZE(control_info) }; struct globals { const char *device_name; /* The width of the screen, for output wrapping */ unsigned max_col; /* Current position, to know when to wrap */ unsigned current_col; char buf[10]; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { \ G.device_name = bb_msg_standard_input; \ G.max_col = 80; \ } while (0) static void set_speed_or_die(enum speed_setting type, const char *arg, struct termios *mode) { speed_t baud; baud = tty_value_to_baud(xatou(arg)); if (type != output_speed) { /* either input or both */ cfsetispeed(mode, baud); } if (type != input_speed) { /* either output or both */ cfsetospeed(mode, baud); } }
const char * const name; /* Name given on command line */ const unsigned char type; /* Which structure element to change */ const unsigned char flags; /* Setting and display options */ /* were using short here, but ppc32 was unhappy: */ const tcflag_t mask; /* Other bits to turn off for this mode */ const tcflag_t bits; /* Bits to set for this mode */ }; /* We can optimize it further by using name[8] instead of char *name */ /* but beware of "if (info->name == evenp)" checks! */ /* Need to replace them with "if (info == &mode_info[EVENP_INDX])" */ #define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B } static const struct mode_info mode_info[] = { MI_ENTRY("parenb", control, REV, PARENB, 0 ), MI_ENTRY("parodd", control, REV, PARODD, 0 ), MI_ENTRY("cs5", control, 0, CS5, CSIZE), MI_ENTRY("cs6", control, 0, CS6, CSIZE), MI_ENTRY("cs7", control, 0, CS7, CSIZE), MI_ENTRY("cs8", control, 0, CS8, CSIZE), MI_ENTRY("hupcl", control, REV, HUPCL, 0 ), MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ), MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ), MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ), MI_ENTRY("clocal", control, REV, CLOCAL, 0 ), #ifdef CRTSCTS MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ), #endif MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ), MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),