/* $Id: ttymodes.c,v 1.19 2007/03/04 13:50:41 tom Exp $ */ #include #include #include /* inflush() */ #undef tabs #ifdef TAB3 # define tabs TAB3 #else # ifdef XTABS # define tabs XTABS # else # ifdef OXTABS # define tabs OXTABS # else # define tabs 0 # endif # endif #endif static TTY old_modes, new_modes; static struct { int name; int code; } speeds[] = { {B0, 0}, {B50, 50}, {B75, 75}, {B110, 110}, {B134, 134}, {B150, 150}, {B200, 200}, {B300, 300}, {B600, 600}, {B1200, 1200}, {B1800, 1800}, {B2400, 2400}, {B4800, 4800}, {B9600, 9600}, #ifdef B19200 {B19200, 19200}, #else #ifdef EXTA {EXTA, 19200}, #endif #endif #ifdef B38400 {B38400, 38400}, #else #ifdef EXTB {EXTB, 38400}, #endif #endif #ifdef B57600 {B57600, 57600}, #endif #ifdef B115200 {B115200, 115200}, #endif }; #if !USE_POSIX_TERMIOS && !USE_TERMIO && USE_SGTTY static struct tchars old_tchars; static struct ltchars old_ltchars; #endif #if USE_POSIX_TERMIOS || USE_TERMIO static void disable_control_chars(TTY *modes) { # if USE_POSIX_TERMIOS int n; int temp; # ifdef HAVE_POSIX_VDISABLE temp = _POSIX_VDISABLE; # else errno = 0; temp = fpathconf(0, _PC_VDISABLE); if (temp == -1) { if (errno != 0) { restore_ttymodes(); fprintf(stderr, "Cannot disable special characters!\n"); exit(EXIT_FAILURE); } temp = 0377; } # endif for (n = 0; n < NCCS; n++) modes->c_cc[n] = temp; # else /* USE_TERMIO */ # ifdef VSWTCH modes->c_cc[VSWTCH] = VDISABLE; # endif modes->c_cc[VSUSP] = VDISABLE; # if defined (VDSUSP) && defined(NCCS) && VDSUSP < NCCS modes->c_cc[VDSUSP] = VDISABLE; # endif modes->c_cc[VSTART] = VDISABLE; modes->c_cc[VSTOP] = VDISABLE; # endif modes->c_cc[VMIN] = 1; modes->c_cc[VTIME] = 0; } #endif static void set_ttymodes(TTY *modes) { # if USE_POSIX_TERMIOS fflush(stdout); tcsetattr(0, TCSAFLUSH, modes); # else # if USE_TERMIO tcsetattr(0, TCSETAF, modes); # else /* USE_SGTTY */ stty(0, modes); # endif # endif } #ifndef log_ttymodes void log_ttymodes(char *file, int line) { if (LOG_ENABLED) fprintf(log_fp, "%s @%d\n", file, line); } #endif #ifndef dump_ttymodes void dump_ttymodes(char *tag, int flag) { #ifdef UNIX TTY tmp_modes; if (LOG_ENABLED) { fprintf(log_fp, "%s (%d):\n", tag, flag); # if USE_POSIX_TERMIOS || USE_TERMIO tcgetattr(0, &tmp_modes); fprintf(log_fp, " iflag %08o\n", tmp_modes.c_iflag); fprintf(log_fp, " oflag %08o\n", tmp_modes.c_oflag); fprintf(log_fp, " lflag %08o\n", tmp_modes.c_lflag); if (!tmp_modes.c_lflag & ICANON) { fprintf(log_fp, " %d:min =%d\n", VMIN, tmp_modes.c_cc[VMIN]); fprintf(log_fp, " %d:time =%d\n", VTIME, tmp_modes.c_cc[VTIME]); } # else gtty(0, &tmp_modes); fprintf(log_fp, " flags %08o\n", tmp_modes.sg_flags); # endif } #endif } #endif void close_tty(void) { restore_ttymodes(); } void init_ttymodes(int pn) { int speed_code, n; dump_ttymodes("init_ttymodes", pn); #ifdef UNIX if (pn==0) { fflush(stdout); # if USE_POSIX_TERMIOS || USE_TERMIO tcgetattr(0, &old_modes); speed_code = cfgetospeed(&old_modes); # else # if USE_SGTTY gtty(0, &old_modes); ioctl(0, TIOCGETC, &old_tchars); ioctl(0, TIOCGLTC, &old_ltchars); speed_code = old_modes.sg_ospeed; # endif # endif new_modes = old_modes; for (n = 0; n < TABLESIZE(speeds); n++) { if (speeds[n].name == speed_code) { tty_speed = speeds[n].code; break; } } } else { putchar(BEL); fflush(stdout); inflush(); new_modes = old_modes; sleep(2); } # if USE_POSIX_TERMIOS || USE_TERMIO new_modes.c_iflag = BRKINT | old_modes.c_iflag; new_modes.c_oflag &= ~tabs; # else /* USE_SGTTY */ new_modes.sg_flags = old_modes.sg_flags | CBREAK; # endif set_ttymodes(&new_modes); # ifdef HAVE_FCNTL_H # ifndef O_NDELAY # define O_NDELAY O_NONBLOCK /* O_NONBLOCK is POSIX */ # endif close(2); open("/dev/tty", O_RDWR|O_NDELAY); # endif #endif /* UNIX */ dump_ttymodes("...init_ttymodes", pn); } void restore_ttymodes(void) { dump_ttymodes("restore_ttymodes", -1); #ifdef UNIX set_ttymodes(&old_modes); #endif dump_ttymodes("...restore_ttymodes", -1); } void set_tty_crmod(int enabled) { dump_ttymodes("set_tty_crmod", enabled); #ifdef UNIX # if USE_POSIX_TERMIOS || USE_TERMIO # if USE_POSIX_TERMIOS # define MASK_CRMOD ((unsigned) (ICRNL | IXON)) # else # define MASK_CRMOD ((unsigned) (ICRNL)) # endif if (enabled) { new_modes.c_iflag |= MASK_CRMOD; new_modes.c_lflag |= ICANON; memcpy(new_modes.c_cc, old_modes.c_cc, sizeof(new_modes.c_cc)); } else { new_modes.c_iflag &= ~MASK_CRMOD; new_modes.c_lflag &= ~ICANON; disable_control_chars(&new_modes); } # else if (enabled) new_modes.sg_flags |= CRMOD; else new_modes.sg_flags &= ~CRMOD; # endif set_ttymodes(&new_modes); #endif dump_ttymodes("...set_tty_crmod", enabled); } void set_tty_echo(int enabled) { dump_ttymodes("set_tty_echo", enabled); #ifdef UNIX # if USE_POSIX_TERMIOS || USE_TERMIO if (enabled) new_modes.c_lflag |= ECHO; else new_modes.c_lflag &= ~ECHO; # else /* USE_SGTTY */ if (enabled) new_modes.sg_flags |= ECHO; else new_modes.sg_flags &= ~ECHO; # endif set_ttymodes(&new_modes); #endif dump_ttymodes("...set_tty_echo", enabled); } void set_tty_raw(int enabled) { dump_ttymodes("set_tty_raw", enabled); if (enabled) { #ifdef UNIX # if USE_POSIX_TERMIOS || USE_TERMIO new_modes.c_iflag = 0; new_modes.c_lflag = 0; new_modes.c_cc[VMIN] = 1; new_modes.c_cc[VTIME] = 0; set_ttymodes(&new_modes); set_tty_crmod(FALSE); # else /* USE_SGTTY */ # ifdef HAVE_FCNTL_H new_modes.sg_flags &= ~CBREAK; # endif new_modes.sg_flags |= RAW; set_ttymodes(&new_modes); { struct tchars tmp_tchars; struct ltchars tmp_ltchars; memset(&tmp_tchars, -1, sizeof(tmp_tchars)); memset(&tmp_ltchars, -1, sizeof(tmp_ltchars)); ioctl(0, TIOCSETC, &tmp_tchars); ioctl(0, TIOCSLTC, &tmp_ltchars); } # endif #endif } else { #ifdef UNIX # if USE_POSIX_TERMIOS || USE_TERMIO new_modes = old_modes; /* FIXME */ # else /* USE_SGTTY */ new_modes.sg_flags &= ~RAW; # ifdef HAVE_FCNTL_H new_modes.sg_flags |= CBREAK; # endif ioctl(0, TIOCSETC, &old_tchars); ioctl(0, TIOCSLTC, &old_ltchars); # endif set_ttymodes(&new_modes); #endif } dump_ttymodes("...set_tty_raw", enabled); }