Hi all, The following program demonstrates what looks to me like a bug in the "read" function in an xterm (as opposed to a Cygwin console window). To run the test, compile with:
gcc -g -o xtermbug.exe xtermbug.c When you run it in a console window, you can enter normal keyboard characters, then a return to see "cmdline=<what you typed>". Press the Esc key to exit the program. When run in an xterm window, the first keypress causes this behavior: 1. Select returns with rc = 0 and readset set to indicate that a key was received 2. "read" returns with kblen = 1 and kbbuf[0] = '\0' 3. (1) and (2) repeat forever. I put in a "maxdbg" parameter and terminate the program after 5 occurrences of this loop. This problem was first detected trying to run a copy of the hercules IBM mainframe emulator in a Cygwin xterm window. The code below is extracted and minimalized as much as possible from the hercules keyboard input routine. Peter Farley xtermbug.c: /*-------------------------------------------------------------------*/ /* This is a test program to show a cygwin xterm bug, possibly */ /* in the read function. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Definitions for keyboard input sequences */ /*-------------------------------------------------------------------*/ #define KBD_DELETE "\x1B[3~" #include <stdio.h> #include <unistd.h> #include <sys/time.h> #include <string.h> #include <errno.h> #include <termios.h> #define MSG_SIZE 80 /* Size of one message */ #define CMD_SIZE 32767 /* Length of command line */ #define BYTE unsigned char int ttyreset = 0; struct termios kbattr; /* Terminal I/O structure */ /*-------------------------------------------------------------------*/ /* xterm display subroutine */ /*-------------------------------------------------------------------*/ void xterm_display (void) { int rc; /* Return code */ int i; /* Array subscripts */ char cmdline[CMD_SIZE+1]; /* Command line buffer */ int cmdoff = 0; /* Cursor position in cmdline*/ int cmdlen = 0; /* Number of bytes in cmdline*/ //BYTE c; /* Character work area */ FILE *confp; /* Console file pointer */ size_t kbbufsize = CMD_SIZE; /* Size of keyboard buffer */ char *kbbuf = NULL; /* Keyboard input buffer */ int kblen; /* Number of chars in kbbuf */ int keybfd; /* Keyboard file descriptor */ int maxfd; /* Highest file descriptor */ fd_set readset; /* Select file descriptors */ struct timeval tv; /* Select timeout structure */ int maxdbg = 0; /* Set up the input file descriptors */ confp = stdout; keybfd = STDIN_FILENO; fprintf(confp, "start kbbuf=%8.8X,&kbbuf=%8.8X\n", kbbuf, &kbbuf); /* Obtain storage for the keyboard buffer */ if (!(kbbuf = (char *)malloc (kbbufsize))) { fprintf(stderr, "HHCPN002S Cannot obtain keyboard buffer: %s\n", strerror(errno)); return; } fprintf(confp, "start kbbuf=%8.8X,&kbbuf=%8.8X,*kbbuf=%8.8X\n", kbbuf, &kbbuf, *kbbuf); /* Set screen output stream to fully buffered */ setvbuf (confp, NULL, _IOFBF, 0); /* Put the terminal into cbreak mode */ tcgetattr (keybfd, &kbattr); kbattr.c_lflag &= ~(ECHO | ICANON); kbattr.c_cc[VMIN] = 0; kbattr.c_cc[VTIME] = 0; tcsetattr (keybfd, TCSANOW, &kbattr); ttyreset = 1; fprintf(confp, "Starting while(1) loop.\n"); fflush(confp); /* Process messages and commands */ while (1) { /* Set the file descriptors for select */ FD_ZERO (&readset); FD_SET (keybfd, &readset); maxfd = keybfd; /* Wait for a key to be pressed, or the inactivity interval to expire */ tv.tv_sec = 1; tv.tv_usec = 1 % 1000000; rc = select (maxfd + 1, &readset, NULL, NULL, &tv); if (rc < 0 ) { if (errno == EINTR) continue; fprintf (stderr, "HHCPN004E select: %s\n", strerror(errno)); break; } fprintf(confp, "rc=%d,readset={%8.8X,%8.8X}\n", rc, readset.fds_bits[0], readset.fds_bits[1]); fflush(confp); /* If keyboard input has arrived then process it */ if (FD_ISSET(keybfd, &readset)) { /* Read character(s) from the keyboard */ kblen = read (keybfd, kbbuf, kbbufsize-1); fprintf(confp, "kblen=%d\n", kblen); if (kblen < 0) { fprintf (stderr, "HHCPN005E keyboard read: %s\n", strerror(errno)); break; } kbbuf[kblen] = '\0'; fprintf(confp, "kbbuf[0-%d]=", kblen); for (i = 0; i <= kblen; i++) { fprintf(confp, "%2.2X", kbbuf[i]); if (i < kblen) fprintf(confp, ","); } fprintf(confp, "\n"); /* Process characters in the keyboard buffer */ for (i = 0; i < kblen; ) { /* Process backspace character */ if (kbbuf[i] == '\b' || kbbuf[i] == '\x7F') { if (cmdoff > 0) { int j; for (j = cmdoff-1; j<cmdlen; j++) cmdline[j] = cmdline[j+1]; cmdoff--; cmdlen--; } i++; break; } /* Process DEL character */ if (strcmp(kbbuf+i, KBD_DELETE) == 0) { if (cmdoff < cmdlen) { int j; for (j = cmdoff; j<cmdlen; j++) cmdline[j] = cmdline[j+1]; cmdlen--; } i++; break; } /* Process escape key */ if (kbbuf[i] == '\x1B') { cmdline[0] = '\0'; cmdoff = 0; cmdlen = 0; /* Restore the terminal mode */ tcgetattr (STDIN_FILENO, &kbattr); kbattr.c_lflag |= (ECHO | ICANON); tcsetattr (STDIN_FILENO, TCSANOW, &kbattr); ttyreset = 0; fprintf(confp, "\n\nTerminating xtermbug test!\n"); fflush(confp); return; } /* Process the command if newline was read */ if (kbbuf[i] == '\n') { fprintf (confp, "\ncmdline=%s\n", cmdline); break; } /* Ignore non-printable characters */ if (!isprint(kbbuf[i])) { fprintf(stderr, "Unprintable:%8.8X\n", *(kbbuf+i)); i++; if (++maxdbg > 5) { return; } break; } /* Append the character to the command buffer */ if (cmdoff < CMD_SIZE-1) { if (cmdoff < cmdlen) { int j; for (j=cmdlen-1; j>=cmdoff; j--) cmdline[j+1] = cmdline[j]; cmdline[cmdoff++] = kbbuf[i]; } else cmdline[cmdoff++] = kbbuf[i]; cmdlen++; } i++; } /* end for(i) */ } } /* end while */ return; } /* end function xterm_display */ int main(int argc, char *argv[]) { xterm_display(); if (ttyreset) { /* Restore the terminal mode */ tcgetattr (STDIN_FILENO, &kbattr); kbattr.c_lflag |= (ECHO | ICANON); tcsetattr (STDIN_FILENO, TCSANOW, &kbattr); } return(0); } __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com