Subject: bugs in noncanonnical termios mode
From: [email-masked] (Hawkeye)

12 Apr 1997 15:16:30 -0700
Approved: [email-masked]
Distribution: cygnus
Message-ID: <[email-masked]>
Content-Type: text
Original-To: [email-masked]
X-Mailer: ELM [version 2.4 PL23]
Original-Sender: [email-masked]

In gnu-win32/cygwin32 b17.1 for Win95, termios noncannonical mode blocks
when it shouldn't, doesn't block when it should, and gets confused by
shift, ctrl, and capslock.  (only ~ICANON seemed to cause the problem; the
other flags in the example program are only there because those are what I
use in the real program I was trying to port).

The example program below takes 4 command line parameters:
1. the maximum number of characters to read()
2. a flag to enable or disable select() before reading
3. termios VMIN
4. termios VTIME

With max>=1 and selectflag==0, the read() always blocked until max chars
were typed, completely ignoring VMIN and VTIME.  Since termios ECHO is on,
it appears likely that the cygwin code is blocked in a windows call, since
not even it echoes until max chars are typed.

With max>=1 and selectflag==1, it got even weirder: for single-keystroke
characters, the read() immediately returned 1 character (even if VMIN>1);
but if SHIFT or CTRL was held, or CAPS LOCK was on, when a key was pressed,
the read() would then block until max chars were typed.

--- cut here ---
#include <unistd.h>
#include <errno.h>
#include <termios.h>
#include <sys/types.h>

struct termios tty, old_tty;

void set_tty(int vmin, int vtime);
void reset_tty(void);

int main(int argc, char *argv[])
{
    char buf[1024];
    int max, selectflag, vmin, vtime;
    int len, count;
    fd_set readers;

    if (argc != 5) exit(1);
    max = atoi(argv[1]);
    selectflag = atoi(argv[2]);
    vmin = atoi(argv[3]);
    vtime = atoi(argv[4]);

    FD_ZERO(&readers);
    set_tty(vmin, vtime);
    while (1) {
        if (selectflag) {
            FD_SET(STDIN_FILENO, &readers);
            count = select(STDIN_FILENO+1, &readers, NULL, NULL, NULL);
            if (count < 0) {
                perror("select");
                break;
            }
        }
        len = read(STDIN_FILENO, buf, max);
        if (len < 0) {
            perror("read");
            break;
        }
        write(STDOUT_FILENO, buf, len);
        if (buf[0] == 'x')
            break;
    }
    reset_tty();
}

void set_tty(int vmin, int vtime)
{
    if (tcgetattr(STDIN_FILENO, &tty) < 0) {
        perror("getattr");
        exit(1);
    }
    old_tty = tty;

    tty.c_lflag &= ~ICANON;
    tty.c_lflag |= ISIG;
    tty.c_iflag |= IGNBRK | IGNPAR;
    tty.c_iflag &= ~(ICRNL | INLCR | ISTRIP | IGNCR);
    tty.c_cc[VMIN] = vmin;
    tty.c_cc[VTIME] = vtime;

    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tty) < 0) {
         perror("setattr");
         exit(1);
    }
}

void reset_tty(void)
{
    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_tty) < 0)
        perror("reset");
}
--- end cut ---

===========================================================================
Ken Keys            [email-masked]            http://tf.tcp.com/~hawkeye/
---------------------------------------------------------------------------
TinyFugue info: http://tf.tcp.com/~hawkeye/tf/
TF version 3.5 beta 4 for UNIX and OS/2 is available at:
  ftp://tf.tcp.com/pub/tinyfugue/ and ftp://ftp.tcp.com/pub/mud/Clients/tf/
TF mailing list: mail to [email-masked], with body "subscribe tinyfugue"
===========================================================================
-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".