select() fails on multi-byte input in cygwin console (since 1.7.10)

Thomas Wolff towo@towo.net
Tue Dec 9 07:02:00 GMT 2014


Calling select() to check whether input from the terminal is available
fails for all but the first byte in the cygwin console if multiple bytes
are entered at once, like function or cursor keys or non-ASCII UTF-8
characters.
Actually, the issue is volatile, sometimes it works for characters and
most function keys.
The problem most likely arises with the escape sequences mouse scroll
and window focus out/in (both enabled by the test program).
I tried to use read() with timeout instead, trying various combinations
of tcsetattr setting VMIN/VTIME, fcntl setting O_NONBLOCK, using read()
with buffer length 0, trying to interrupt read() with a timer signal, or
even a combination of setitimer() and siglongjmp().
None of this works.

Thanks to the cygwin time machine, I could track back this bug to have
appeared in 1.7.10 (around the time I had reported another select()
issue: https://sourceware.org/ml/cygwin/2011-05/msg00418.html which I
hope doesn’t interfere, nor the later issue
https://sourceware.org/ml/cygwin/2013-01/msg00139.html).

------
Thomas



---
Diese E-Mail wurde von Avast Antivirus-Software auf Viren geprüft.
http://www.avast.com
-------------- next part --------------
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#include <sys/select.h>
#include <time.h>
#include <signal.h>

struct termios saved_tattr;

void
restore_tattr (void)
{
  if (isatty (STDIN_FILENO))
    tcsetattr (STDIN_FILENO, TCSANOW, &saved_tattr);
}

int
ready_select ()
{
  struct timeval timeoutstru;
  fd_set readfds;
  int nfds;
  static int rv = 0;

  timeoutstru.tv_sec = 0;
  timeoutstru.tv_usec = 800000;

  FD_ZERO (& readfds);
  FD_SET (STDIN_FILENO, & readfds);
  nfds = select (STDIN_FILENO + 1, & readfds, 0, 0, & timeoutstru);
  printf ("(%d)", nfds);
  return nfds;
}

int
main (void)
{
  if (isatty (STDIN_FILENO)) {
    struct termios tattr;
    tcgetattr (STDIN_FILENO, &saved_tattr);
    tattr = saved_tattr;
/*
    tattr.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
    tattr.c_oflag &= ~OPOST;
    tattr.c_cflag &= ~(CSIZE|PARENB);
    tattr.c_cflag |= CS8;
    tattr.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
*/
    /* use miminal change for test case: */
    tattr.c_lflag &= ~(ICANON);
    tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr);
    atexit (restore_tattr);
  }
  setbuf (stdout, 0);

  printf ("\033[?1000h\033[?1006h\033[?1004h");
  while (1) {
    unsigned char c;
    int res;

    while (! ready_select ()) {
    }

    res = read (STDIN_FILENO, & c, 1);
    switch (c & 0xFF) {
      case 0x00 ... 0x1f:  putchar ('^'); putchar (c + 0x40);
                           if (c == '\r') printf ("\r\n");
                           break;
      case 0x7f: putchar ('^'); putchar ('?'); break;
      case 0x80 ... 0xFF: printf ("\\x%2X", c); break;
      default: putchar (c);
    }
    fflush (stdout);
  }
  printf ("\033[?1000l\033[?1004l\r\nbye\r\n");
  return 0;
}
-------------- next part --------------
--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


More information about the Cygwin mailing list