This is the mail archive of the cygwin-xfree@cygwin.com mailing list for the Cygwin XFree86 project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

read bug in Cygwin xterm window only


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 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]