This is the mail archive of the
cygwin-xfree@cygwin.com
mailing list for the Cygwin XFree86 project.
read bug in Cygwin xterm window only
- From: Peter Farley <pjfarley3 at yahoo dot com>
- To: cygwin-xfree at cygwin dot com
- Date: Fri, 29 Apr 2005 17:54:35 -0700 (PDT)
- Subject: read bug in Cygwin xterm window only
- Reply-to: cygwin-xfree at cygwin dot com
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