Net2/usr/src/contrib/isode/others/X/client/XlibInt.c

Compare this file to the similar file:
Show the results in this format:

/*
 * $XConsortium: XlibInt.c,v 11.90 88/09/30 17:25:18 jim Exp $
 */

#include "copyright.h"
/* Copyright    Massachusetts Institute of Technology    1985, 1986, 1987 */

/*
 *	XlibInternal.c - Internal support routines for the C subroutine
 *	interface library (Xlib) to the X Window System Protocol V11.0.
 */
#define NEED_EVENTS
#define NEED_REPLIES

#include <stdio.h>
#include "Xlibint.h"

#ifdef ISOCONN
#include <isode/psap.h>
#include <isode/tsap.h>
#include <isode/isoservent.h>

#endif /* ISOCONN */

#ifdef CRAY

/*
 * Cray UniCOS does not have readv and writev so we emulate
 */
#include <sys/socket.h>

static int readv (fd, iov, iovcnt)
int fd;
struct iovec *iov;
int iovcnt;
{
	struct msghdr hdr;

	hdr.msg_iov = iov;
	hdr.msg_iovlen = iovcnt;
	hdr.msg_accrights = 0;
	hdr.msg_accrightslen = 0;
	hdr.msg_name = 0;
	hdr.msg_namelen = 0;

	return (recvmsg (fd, &hdr, 0));
}

static int writev (fd, iov, iovcnt)
int fd;
struct iovec *iov;
int iovcnt;
{
	struct msghdr hdr;

	hdr.msg_iov = iov;
	hdr.msg_iovlen = iovcnt;
	hdr.msg_accrights = 0;
	hdr.msg_accrightslen = 0;
	hdr.msg_name = 0;
	hdr.msg_namelen = 0;

	return (sendmsg (fd, &hdr, 0));
}

#endif /* CRAY */

#ifdef ISOCONN
/*
 * Need these Convenience routines to map IO to T-service 
 * XXX
 * Should map error returns in td->td_reason into
 * errno's appropriately...
 */

/*
 * Check if any bytes queued that could be read...
 */
TBytesReadable(fd, ptr)
int fd;
long *ptr;
{
	struct TSAPdisconnect tds;
        struct TSAPdisconnect *td = &tds;
	int ret = TSelectOctets (fd, ptr, td);
	if (ret == NOTOK) {
		    fprintf(stderr, "Client TBytesReadable: %s\n", 
			TErrString(td->td_reason));
	}
	return ret;
}

/*
 * need followinf for arg mismatch
 */
UBytesReadable(fd, ptr)
int fd;
long *ptr;
{
	return ioctl(fd, FIONREAD, ptr);
}

/* 
 * Simple read from transport cx, client
 */
TReadFromServer(fd, data, size)
int fd;
unsigned size;
char *data;
{
	char *aptr = data;
	struct TSAPdisconnect tds;
	struct TSAPdisconnect *td = &tds;
static struct TSAPdata txs;
static struct TSAPdata *tx = &txs;
static struct qbuf *qb;
static char *qptr;
static int ingot, qcpy, result = 0;
	int q2data, ret;

#ifdef ISODEBUG
	if (isodexbug) {
		fprintf(stderr, "TReadFromServer %d want %d (%d buffered)\n", 
			fd, size, result);
	}
#endif /* ISODEBUG */
	if (result == 0) {
		if ((ret = TReadRequest(fd, tx, OK, td)) == NOTOK) {
#ifdef ISODEBUG
		    if (errno == EWOULDBLOCK) {
			fprintf(stderr, "Client TReadReq would block: %s\n", 
				TErrString(td->td_reason));
			if (!DR_FATAL(td->td_reason))
				errno = EWOULDBLOCK;
			else
				errno = EBADF;
			return ret;
		    }
		    if (isodexbug)
			    fprintf(stderr, "Client TReadReq: %s\n", 
				TErrString(td->td_reason));
#endif /* ISODEBUG */
/*
 * map problems here - eg fTimeOut...
 */
		    if (td->td_reason == DR_TIMER)
			errno = EWOULDBLOCK;
		    return ret;
		}
		result = tx->tx_cc;
		qb = &(tx->tx_qbuf);
		qptr = qb->qb_data;
#ifdef ISODEBUG
		if (isodexbug)
			fprintf(stderr, "TReadRequest want %d got %d\n", 
				size, result);
#endif
	} 
#ifdef ISODEBUG
	else {
		if (isodexbug)
			fprintf(stderr, "TReadFromServer want %d buffered %d\n",
				 size, result);
	}
#endif
/*
 * Buffer it
 */
        ingot = 0;
        aptr = data;
	for(ingot = 0, aptr = data, q2data = min(size, result); 
		ingot<q2data;
		aptr += qcpy, ingot+= qcpy) {
	    int aleft = q2data - ingot;
	    if (qb->qb_len > aleft) {
		    qcpy = aleft;
		    bcopy(qptr, aptr, qcpy);
		    qptr += aleft;
	    } else {
		    qcpy = qb->qb_len;
		    bcopy(qb->qb_data, aptr, qcpy);
		    if ((qb = qb->qb_forw) == NULL)
			break;
		    qptr = qb->qb_data;
	    }
        }
	if ((result -= ingot) <= 0) {
		result = 0;
		TXFREE(tx);
	}
	return ingot;

}

/*
 * Simple write on transport descriptor client
 */
TWriteToServer(fd, data, size)
int fd;
unsigned size;
char *data;
{
	struct TSAPdisconnect tds;
        struct TSAPdisconnect *td = &tds;

#ifdef ISODEBUG
	if (isodexbug)
		fprintf(stderr, "TWriteToServer %d: %d\n", fd, size);
#endif
	if (TDataRequest(fd, data, size, td) == NOTOK) {
		if (errno != EWOULDBLOCK)
			fprintf(stderr, "Client TDataReq: %s\n", 
				TErrString(td->td_reason));
		return -1;
	} else
		return size;
}

/*
 * This is really disgusting, as we do 2 copies - one qbuf into data,
 * one data into iovecs...should really do something utterly neater or
 * ask mtr to provide another T-Service interface for pre-alloced
 * bufs - ideally iovec style
 *
 * or change the structure of X to do async...
 */
TReadvFromServer(fd, iov, iovcnt)
int fd, iovcnt;
struct iovec *iov;
{
	int i, size, result, left, bcp; 
	char *data, *dp;
	struct iovec *iovp;

	for(i=0, size = 0, iovp = iov; i < iovcnt; i++, iovp++)
		size += iovp->iov_len;

#ifdef ISODEBUG
	if (isodexbug)
		fprintf(stderr, "TReadvFromServer %d, want %d\n", fd, size);
#endif
	if ((data = Xmalloc(size)) == NULL) {
#ifdef ISODEBUG
	    if (isodexbug)
		    fprintf(stderr, "TReadvFromServer, malloc failed\n");
#endif
/*
 * Could map to EWOULDBLOCK...?
 */
	    return(-1);
	}

/*
 * Note, TReadFromServer is written to *NOT* return more than size
 */
	if ((result = TReadFromServer(fd, data, size)) == NOTOK) {
	    if (errno != EWOULDBLOCK)
		    fprintf(stderr, "TReadvReq err\n");
	    return(-1);
	}

	left = result;
	dp = data;
	while (left > 0) {
	    bcp = iov->iov_len;
	    if (bcp > left )
		bcp = left;
	    bcopy(dp, iov->iov_base, bcp);
	    if (bcp < left)
		iov++;
	    dp += bcp;
	    left -= bcp;
	}
	Xfree(data);
	return result;
}

/*
 * scatter gather write to transport descriptor
 */
TWritevToServer(fd, iov, iovcnt)
int fd, iovcnt;
struct iovec *iov;
{
	struct TSAPdisconnect tds;
	struct TSAPdisconnect *td = &tds;
	struct udvec uv[64], *uvp;
	int i, ret, tot = 0;

/*
 * Yuck needs dynamicising, or else rely on
 * iov's being same as uv's
 */
	if (iovcnt >= 64) {
		fprintf(stderr, "Very Bad News i am afraid\n");
		return -99;
	}
	for (i=0, uvp = uv; i<iovcnt; uvp++, iov++, i++) {
		uvp->uv_base = iov->iov_base;
		uvp->uv_len = iov->iov_len;
		tot += uvp->uv_len;
	}
#ifdef ISODEBUG
	if (isodexbug)
		fprintf(stderr, "TWritevToServer %d: %d\n",fd, tot);
#endif
	uv[iovcnt].uv_base = NULLCP;
	uv[iovcnt].uv_len = 0;
	if ((ret = TWriteRequest(fd, uv, td)) == NOTOK) {
	    if (errno != EWOULDBLOCK)
		    fprintf(stderr, "Client TReadReq: %s\n", TErrString(td->td_reason));
	    return -1;	
	}
	return tot;
}

TDiscFromServer(fd)
int fd;
{
	struct TSAPdisconnect tds;
        struct TSAPdisconnect *td = &tds;

        if (TDiscRequest(fd, NULLCP, 0, td) == NOTOK)
                fprintf(stderr, "TDR failed %s\n", TErrString(td->td_reason));
}

#endif /* ISOCONN */

/*
 * The following routines are internal routines used by Xlib for protocol
 * packet transmission and reception.
 *
 * XIOError(Display *) will be called if any sort of system call error occurs.
 * This is assumed to be a fatal condition, i.e., XIOError should not return.
 *
 * XError(Display *, XErrorEvent *) will be called whenever an X_Error event is
 * received.  This is not assumed to be a fatal condition, i.e., it is
 * acceptable for this procedure to return.  However, XError should NOT
 * perform any operations (directly or indirectly) on the DISPLAY.
 *
 * Routines declared with a return type of 'Status' return 0 on failure,
 * and non 0 on success.  Routines with no declared return type don't 
 * return anything.  Whenever possible routines that create objects return
 * the object they have created.
 */

_XQEvent *_qfree = NULL;			/* NULL _XQEvent. */

static int padlength[4] = {0, 3, 2, 1};
    /* lookup table for adding padding bytes to data that is read from
    	or written to the X socket.  */

static xReq _dummy_request = {
	0, 0, 0
};
/*
 * _XFlush - Flush the X request buffer.  If the buffer is empty, no
 * action is taken.  This routine correctly handles incremental writes.
 * This routine may have to be reworked if int < long.
 */
_XFlush (dpy)
	register Display *dpy;
{
	register long size, todo;
	register int write_stat;
	register char *bufindex;

	size = todo = dpy->bufptr - dpy->buffer;
	bufindex = dpy->bufptr = dpy->buffer;
	/*
	 * While write has not written the entire buffer, keep looping
	 * until the entire buffer is written.  bufindex will be incremented
	 * and size decremented as buffer is written out.
	 */
	while (size) {
	    errno = 0;
	    write_stat = WriteToServer(dpy->fd, bufindex, (int) todo);
	    if (write_stat >= 0) {
		size -= write_stat;
		todo = size;
		bufindex += write_stat;
#ifdef EWOULDBLOCK
	    } else if (errno == EWOULDBLOCK) {
		_XWaitForWritable(dpy);
#endif
#ifdef SUNSYSV
	    } else if (errno == 0) {
		_XWaitForWritable(dpy);
#endif
#ifdef EMSGSIZE
	    } else if (errno == EMSGSIZE) {
		todo >>= 1;
#endif
	    } else {
		/* Write failed! */
		/* errno set by write system call. */
		(*_XIOErrorFunction)(dpy);
	    }
	}
	dpy->last_req = (char *)&_dummy_request;
}

int
_XEventsQueued (dpy, mode)
    register Display *dpy;
    int mode;
{
	register int len;
	int pend;
	char buf[BUFSIZE];
	register xReply *rep;
	
	if (mode == QueuedAfterFlush)
	    _XFlush(dpy);
	if (BytesReadable(dpy->fd, (char *) &pend) < 0)
	    (*_XIOErrorFunction)(dpy);
	if ((len = pend) < SIZEOF(xReply))
	    return(dpy->qlen);	/* _XFlush can enqueue events */
	else if (len > BUFSIZE)
	    len = BUFSIZE;
	len /= SIZEOF(xReply);
	pend = len * SIZEOF(xReply);
	_XRead (dpy, buf, (long) pend);

	/* no space between comma and type or else macro will die */
	STARTITERATE (rep,xReply, buf, (len > 0), len--) {
	    if (rep->generic.type == X_Error)
		_XError(dpy, (xError *)rep);
	    else   /* must be an event packet */
		_XEnq(dpy, (xEvent *) rep);
	}
	ENDITERATE
	return(dpy->qlen);
}

/* _XReadEvents - Flush the output queue,
 * then read as many events as possible (but at least 1) and enqueue them
 */
_XReadEvents(dpy)
	register Display *dpy;
{
	char buf[BUFSIZE];
	long pend_not_register; /* because can't "&" a register variable */
	register long pend;
	register xEvent *ev;
	Bool not_yet_flushed = True;

	do {
	    /* find out how much data can be read */
	    if (BytesReadable(dpy->fd, (char *) &pend_not_register) < 0)
	    	(*_XIOErrorFunction)(dpy);
	    pend = pend_not_register;

	    /* must read at least one xEvent; if none is pending, then
	       we'll just flush and block waiting for it */
	    if (pend < SIZEOF(xEvent)) {
	    	pend = SIZEOF(xEvent);
		/* don't flush until we block the first time */
		if (not_yet_flushed) {
		    int qlen = dpy->qlen;
		    _XFlush (dpy);
		    if (qlen != dpy->qlen) return;
		    not_yet_flushed = False;
		}
	    }
		
	    /* but we won't read more than the max buffer size */
	    if (pend > BUFSIZE)
	    	pend = BUFSIZE;

	    /* round down to an integral number of XReps */
	    pend = (pend / SIZEOF(xEvent)) * SIZEOF(xEvent);

	    _XRead (dpy, buf, pend);

	    /* no space between comma and type or else macro will die */
	    STARTITERATE (ev,xEvent, buf, (pend > 0),
			  pend -= SIZEOF(xEvent)) {
		if (ev->u.u.type == X_Error)
		    _XError (dpy, (xError *) ev);
		else  /* it's an event packet; enqueue it */
		    _XEnq (dpy, ev);
	    }
	    ENDITERATE
	} while (dpy->head == NULL);
}

/* 
 * _XRead - Read bytes from the socket taking into account incomplete
 * reads.  This routine may have to be reworked if int < long.
 */
_XRead (dpy, data, size)
	register Display *dpy;
	register char *data;
	register long size;
{
	register long bytes_read;

	if (size == 0) return;
	errno = 0;
	while ((bytes_read = ReadFromServer(dpy->fd, data, (int)size))
		!= size) {

	    	if (bytes_read > 0) {
		    size -= bytes_read;
		    data += bytes_read;
		    }
#ifdef EWOULDBLOCK
		else if (errno == EWOULDBLOCK) {
		    _XWaitForReadable(dpy);
		    errno = 0;
		}
#endif		
#ifdef SUNSYSV
		else if (errno == 0) {
		    _XWaitForReadable(dpy);
		}
#endif
		else if (bytes_read == 0) {
		    /* Read failed because of end of file! */
		    errno = EPIPE;
		    (*_XIOErrorFunction)(dpy);
		    }

		else  /* bytes_read is less than 0; presumably -1 */ {
		    /* If it's a system call interrupt, it's not an error. */
		    if (errno != EINTR)
		    	(*_XIOErrorFunction)(dpy);
		    }
	    	 }
}

#ifdef WORD64

/*
 * XXX This is a *really* stupid way of doing this....
 */

#define PACKBUFFERSIZE 4096


/*
 * _XRead32 - Read bytes from the socket unpacking each 32 bits
 *            into a long (64 bits on a CRAY computer).
 * 
 */
static _doXRead32 (dpy, data, size, packbuffer)
        register Display *dpy;
        register long *data;
        register long size;
	register char *packbuffer;
{
 long *lpack,*lp;
 long mask32 = 0x00000000ffffffff;
 long maskw, nwords, i, bits;

        _XReadPad (dpy, packbuffer, size);

        lp = data;
        lpack = (long *) packbuffer;
        nwords = size >> 2;
        bits = 32;

        for(i=0;i<nwords;i++){
            maskw = mask32 << bits;
           *lp++ = ( *lpack & maskw ) >> bits;
            bits = bits ^32;
            if(bits){
               lpack++;
            }
        }
}

_XRead32 (dpy, data, len)
    Display *dpy;
    long *data;
    long len;
{
    char packbuffer[PACKBUFFERSIZE];
    unsigned nwords = (PACKBUFFERSIZE >> 2);	/* bytes to CARD32 */

    for (; len > nwords; len -= nwords, data += nwords) {
	_doXRead32 (dpy, data, nwords, packbuffer);
    }
    _doXRead32 (dpy, data, len, packbuffer);
}



/*
 * _XRead16 - Read bytes from the socket unpacking each 16 bits
 *            into a long (64 bits on a CRAY computer).
 *
 */
static _doXRead16 (dpy, data, size, packbuffer)
        register Display *dpy;
        register short *data;
        register long size;
	char *packbuffer;
{
	long *lpack,*lp;
	long mask16 = 0x000000000000ffff;
	long maskw, nwords, i, bits;

        _XRead(dpy,packbuffer,size);	/* don't do a padded read... */

        lp = (long *) data;
        lpack = (long *) packbuffer;
        nwords = size >> 1;  /* number of 16 bit words to be unpacked */
        bits = 48;
        for(i=0;i<nwords;i++){
            maskw = mask16 << bits;
           *lp++ = ( *lpack & maskw ) >> bits;
            bits -= 16;
            if(bits < 0){
               lpack++;
               bits = 48;
            }
        }
}

_XRead16 (dpy, data, len)
    Display *dpy;
    short *data;
    long len;
{
    char packbuffer[PACKBUFFERSIZE];
    unsigned nwords = (PACKBUFFERSIZE >> 1);	/* bytes to CARD16 */

    for (; len > nwords; len -= nwords, data += nwords) {
	_doXRead16 (dpy, data, nwords, packbuffer);
    }
    _doXRead16 (dpy, data, len, packbuffer);
}

_XRead16Pad (dpy, data, size)
    Display *dpy;
    short *data;
    long size;
{
    int slop = (size & 3);
    short slopbuf[3];

    _XRead16 (dpy, data, size);
    if (slop > 0) {
	_XRead16 (dpy, slopbuf, 4 - slop);
    }
}
#endif /* WORD64 */


/*
 * _XReadPad - Read bytes from the socket taking into account incomplete
 * reads.  If the number of bytes is not 0 mod 32, read additional pad
 * bytes. This routine may have to be reworked if int < long.
 */
_XReadPad (dpy, data, size)
    	register Display *dpy;	
	register char *data;
	register long size;
{
    	register long bytes_read;
	struct iovec iov[2];
	char pad[3];

	if (size == 0) return;
	iov[0].iov_len = (int)size;
	iov[0].iov_base = data;
	/* 
	 * The following hack is used to provide 32 bit long-word
	 * aligned padding.  The [1] vector is of length 0, 1, 2, or 3,
	 * whatever is needed.
	 */

	iov[1].iov_len = padlength[size & 3];
	iov[1].iov_base = pad;
	size += iov[1].iov_len;

	errno = 0;
	while ((bytes_read = ReadvFromServer (dpy->fd, iov, 2)) != size) {

	    if (bytes_read > 0) {
		size -= bytes_read;
	    	if ((iov[0].iov_len -= bytes_read) < 0) {
		    iov[1].iov_len += iov[0].iov_len;
		    iov[1].iov_base -= iov[0].iov_len;
		    iov[0].iov_len = 0;
		    }
	    	else
	    	    iov[0].iov_base += bytes_read;
	    	}
#ifdef EWOULDBLOCK
	    else if (errno == EWOULDBLOCK) {
		_XWaitForReadable(dpy);
		errno = 0;
	    }
#endif
#ifdef SUNSYSV
	    else if (errno == 0) {
		_XWaitForReadable(dpy);
	    }
#endif
	    else if (bytes_read == 0) {
		/* Read failed because of end of file! */
		errno = EPIPE;
		(*_XIOErrorFunction)(dpy);
		}
	    
	    else  /* bytes_read is less than 0; presumably -1 */ {
		/* If it's a system call interrupt, it's not an error. */
		if (errno != EINTR)
		    (*_XIOErrorFunction)(dpy);
		}
	    }

}

/*
 * _XSend - Flush the buffer and send the client data. 32 bit word aligned
 * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
 * This routine may have to be reworked if int < long;
 */
_XSend (dpy, data, size)
	register Display *dpy;
	char *data;
	register long size;
{
	struct iovec iov[3];
	static char pad[3] = {0, 0, 0};
           /* XText8 and XText16 require that the padding bytes be zero! */

	long skip = 0;
	long total = (dpy->bufptr - dpy->buffer) + ((size + 3) & ~3);
	long todo = total;

	while (total) {
	    long before = skip;
	    long remain = todo;
	    int i = 0;
	    long len;

	/* You could be very general here and have "in" and "out" iovecs
	 * and write a loop without using a macro, but what the heck
	 */

#define InsertIOV(pointer, length) \
	    len = (length) - before; \
	    if (len > remain) \
		len = remain; \
	    if (len <= 0) { \
		before = -len; \
	    } else { \
		iov[i].iov_len = len; \
		iov[i].iov_base = (pointer) + before; \
		i++; \
		remain -= len; \
		before = 0; \
	    }

	    InsertIOV(dpy->buffer, dpy->bufptr - dpy->buffer)
	    InsertIOV(data, size)
	    /* Provide 32-bit aligned padding as necessary */
	    InsertIOV(pad, padlength[size & 3])
    
	    errno = 0;
	    if ((len = WritevToServer(dpy->fd, iov, i)) >= 0) {
		skip += len;
		total -= len;
		todo = total;
#ifdef EWOULDBLOCK
	    } else if (errno == EWOULDBLOCK) {
		_XWaitForWritable(dpy);
#endif
#ifdef SUNSYSV
	    } else if (errno == 0) {
		_XWaitForWritable(dpy);
#endif
#ifdef EMSGSIZE
	    } else if (errno == EMSGSIZE) {
		todo = todo >> 1;
#endif
	    } else {
		(*_XIOErrorFunction)(dpy);
	    }
	}

	dpy->bufptr = dpy->buffer;
	dpy->last_req = (char *) & _dummy_request;
}

/*
 * _XAllocID - normal resource ID allocation routine.  A client
 * can roll his own and instatantiate it if he wants, but must
 * follow the rules.
 */
XID _XAllocID(dpy)
register Display *dpy;
{
   return (dpy->resource_base + (dpy->resource_id++ << dpy->resource_shift));
}

/*
 * The hard part about this is that we only get 16 bits from a reply.  Well,
 * then, we have three values that will march along, with the following
 * invariant:
 *	dpy->last_request_read <= rep->sequenceNumber <= dpy->request
 * The right choice for rep->sequenceNumber is the largest that
 * still meets these constraints.
 */
static unsigned long
_SetLastRequestRead(dpy, rep)
    register Display *dpy;
    register xGenericReply *rep;
{
    register unsigned long	newseq, lastseq;

    /*
     * KeymapNotify has no sequence number, but is always guaranteed
     * to immediately follow another event, except when generated via
     * SendEvent (hmmm).
     */
    if ((rep->type & 0x7f) == KeymapNotify)
	return(dpy->last_request_read);

    newseq = (dpy->last_request_read & ~((unsigned long)0xffff)) |
	     rep->sequenceNumber;
    lastseq = dpy->last_request_read;
    while (newseq < lastseq) {
	newseq += 0x10000;
	if (newseq > dpy->request) {
	    (void) fprintf (stderr, 
	    "Xlib:  sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n",
	                           newseq, dpy->request, 
				   (unsigned int) rep->type);
	    newseq -= 0x10000;
	    break;
	}
    }

    dpy->last_request_read = newseq;
    return(newseq);
}

/*
 * _XReply - Wait for a reply packet and copy its contents into the
 * specified rep.  Mean while we must handle error and event packets that
 * we may encounter.
 */
Status _XReply (dpy, rep, extra, discard)
    register Display *dpy;
    register xReply *rep;
    int extra;		/* number of 32-bit words expected after the reply */
    Bool discard;	/* should I discard data followind "extra" words? */
{
    /* Pull out the serial number now, so that (currently illegal) requests
     * generated by an error handler don't confuse us.
     */
    unsigned long cur_request = dpy->request;

    _XFlush(dpy);
    while (1) {
	_XRead(dpy, (char *)rep, (long)SIZEOF(xReply));
	switch ((int)rep->generic.type) {

	    case X_Reply:
	        /* Reply received.  Fast update for synchronous replies,
		 * but deal with multiple outstanding replies.
		 */
	        if (rep->generic.sequenceNumber == (cur_request & 0xffff))
		    dpy->last_request_read = cur_request;
		else
		    (void) _SetLastRequestRead(dpy, &rep->generic);
		if (extra == 0) {
		    if (discard && (rep->generic.length > 0))
		       /* unexpectedly long reply! */
		       _EatData (dpy, rep->generic.length);
		    return (1);
		    }
		if (extra == rep->generic.length) {
		    /* 
		     * Read the extra data into storage immediately following
		     * the GenericReply structure. 
		     */
		    _XRead (dpy, NEXTPTR(rep,xReply), ((long)extra) << 2);
		    return (1);
		    }
		if (extra < rep->generic.length) {
		    /* Actual reply is longer than "extra" */
		    _XRead (dpy, NEXTPTR(rep,xReply), ((long)extra) << 2);
		    if (discard)
		        _EatData (dpy, rep->generic.length - extra);
		    return (1);
		    }
		/* 
		 *if we get here, then extra > rep->generic.length--meaning we
		 * read a reply that's shorter than we expected.  This is an 
		 * error,  but we still need to figure out how to handle it...
		 */
		_XRead (dpy, NEXTPTR(rep,xReply),
			((long) rep->generic.length) << 2);
		(*_XIOErrorFunction) (dpy);
		return (0);

    	    case X_Error:
	    	{
	        register _XExtension *ext;
		register Bool ret = False;
		int ret_code;
		xError *err = (xError *) rep;
		unsigned long serial;

		serial = _SetLastRequestRead(dpy, (xGenericReply *)rep);
		if (serial == cur_request)
			/* do not die on "no such font", "can't allocate",
			   "can't grab" failures */
			switch ((int)err->errorCode) {
			case BadName:
			    switch (err->majorCode) {
				case X_OpenFont:
				case X_LookupColor:
				case X_AllocNamedColor:
				    return(0);
			    }
			    break;
			case BadFont:
			    if (err->majorCode == X_QueryFont)
				return (0);
			    break;
			case BadAlloc:
			case BadAccess:
				return (0);
			/* 
			 * we better see if there is an extension who may
			 * want to suppress the error.
			 */
			default:
			    ext = dpy->ext_procs;
			    while (ext) {
				if (ext->error != NULL) 
				   ret = (*ext->error)
					(dpy, err, &ext->codes, &ret_code);
				ext = ext->next;
				}
			    if (ret) return (ret_code);
			    break;
			}
		_XError(dpy, err);
		if (serial == cur_request)
		    return(0);
		}
		break;
	    default:
		_XEnq(dpy, (xEvent *) rep);
		break;
	    }
	}
}   


/* Read and discard "n" 32-bit words. */

static _EatData (dpy, n)
    Display *dpy;
    unsigned long n;
    {
    unsigned int bufsize;
    char *buf;
    n <<= 2;  /* convert to number of bytes */
    buf = Xmalloc (bufsize = (n > 2048) ? 2048 : n);
    while (n) {
	long bytes_read = (n > bufsize) ? bufsize : n;
	_XRead (dpy, buf, bytes_read);
	n -= bytes_read;
	}
    Xfree (buf);
    }

/*
 * _XEnq - Place event packets on the display's queue.
 * note that no squishing of move events in V11, since there
 * is pointer motion hints....
 */
_XEnq (dpy, event)
	register Display *dpy;
	register xEvent *event;
{
	register _XQEvent *qelt;

/*NOSTRICT*/
	if (qelt = _qfree) {
		/* If _qfree is non-NULL do this, else malloc a new one. */
		_qfree = qelt->next;
	}
	else if ((qelt = 
	    (_XQEvent *) Xmalloc((unsigned)sizeof(_XQEvent))) == NULL) {
		/* Malloc call failed! */
		errno = ENOMEM;
		(*_XIOErrorFunction)(dpy);
	}
	qelt->next = NULL;
	/* go call through display to find proper event reformatter */
	if ((*dpy->event_vec[event->u.u.type & 0177])(dpy, &qelt->event, event)) {
	    if (dpy->tail)	dpy->tail->next = qelt;
	    else 		dpy->head = qelt;
    
	    dpy->tail = qelt;
	    dpy->qlen++;
	} else {
	    /* ignored, or stashed away for many-to-one compression */
	    qelt->next = _qfree;
	    _qfree = qelt;
	}
}
/*
 * EventToWire in seperate file in that often not needed.
 */

/*ARGSUSED*/
Bool
_XUnknownWireEvent(dpy, re, event)
register Display *dpy;	/* pointer to display structure */
register XEvent *re;	/* pointer to where event should be reformatted */
register xEvent *event;	/* wire protocol event */
{
#ifdef notdef
	(void) fprintf(stderr, 
	    "Xlib: unhandled wire event! event number = %d, display = %x\n.",
			event->u.u.type, dpy);
#endif
	return(False);
}

/*ARGSUSED*/
Status
_XUnknownNativeEvent(dpy, re, event)
register Display *dpy;	/* pointer to display structure */
register XEvent *re;	/* pointer to where event should be reformatted */
register xEvent *event;	/* wire protocol event */
{
#ifdef notdef
	(void) fprintf(stderr, 
 	   "Xlib: unhandled native event! event number = %d, display = %x\n.",
			re->type, dpy);
#endif
	return(0);
}
/*
 * reformat a wire event into an XEvent structure of the right type.
 */
Bool
_XWireToEvent(dpy, re, event)
register Display *dpy;	/* pointer to display structure */
register XEvent *re;	/* pointer to where event should be reformatted */
register xEvent *event;	/* wire protocol event */
{

	re->type = event->u.u.type & 0x7f;
	((XAnyEvent *)re)->serial = _SetLastRequestRead(dpy,
					(xGenericReply *)event);
	((XAnyEvent *)re)->send_event = ((event->u.u.type & 0x80) != 0);
	((XAnyEvent *)re)->display = dpy;
	
	/* Ignore the leading bit of the event type since it is set when a
		client sends an event rather than the server. */

	switch (event-> u.u.type & 0177) {
	      case KeyPress:
	      case KeyRelease:
	        {
			register XKeyEvent *ev = (XKeyEvent*) re;
			ev->root 	= event->u.keyButtonPointer.root;
			ev->window 	= event->u.keyButtonPointer.event;
			ev->subwindow 	= event->u.keyButtonPointer.child;
			ev->time 	= event->u.keyButtonPointer.time;
			ev->x 		= event->u.keyButtonPointer.eventX;
			ev->y 		= event->u.keyButtonPointer.eventY;
			ev->x_root 	= event->u.keyButtonPointer.rootX;
			ev->y_root 	= event->u.keyButtonPointer.rootY;
			ev->state	= event->u.keyButtonPointer.state;
			ev->same_screen	= event->u.keyButtonPointer.sameScreen;
			ev->keycode 	= event->u.u.detail;
		}
	      	break;
	      case ButtonPress:
	      case ButtonRelease:
	        {
			register XButtonEvent *ev =  (XButtonEvent *) re;
			ev->root 	= event->u.keyButtonPointer.root;
			ev->window 	= event->u.keyButtonPointer.event;
			ev->subwindow 	= event->u.keyButtonPointer.child;
			ev->time 	= event->u.keyButtonPointer.time;
			ev->x 		= event->u.keyButtonPointer.eventX;
			ev->y 		= event->u.keyButtonPointer.eventY;
			ev->x_root 	= event->u.keyButtonPointer.rootX;
			ev->y_root 	= event->u.keyButtonPointer.rootY;
			ev->state	= event->u.keyButtonPointer.state;
			ev->same_screen	= event->u.keyButtonPointer.sameScreen;
			ev->button 	= event->u.u.detail;
		}
	        break;
	      case MotionNotify:
	        {
			register XMotionEvent *ev =   (XMotionEvent *)re;
			ev->root 	= event->u.keyButtonPointer.root;
			ev->window 	= event->u.keyButtonPointer.event;
			ev->subwindow 	= event->u.keyButtonPointer.child;
			ev->time 	= event->u.keyButtonPointer.time;
			ev->x 		= event->u.keyButtonPointer.eventX;
			ev->y 		= event->u.keyButtonPointer.eventY;
			ev->x_root 	= event->u.keyButtonPointer.rootX;
			ev->y_root 	= event->u.keyButtonPointer.rootY;
			ev->state	= event->u.keyButtonPointer.state;
			ev->same_screen	= event->u.keyButtonPointer.sameScreen;
			ev->is_hint 	= event->u.u.detail;
		}
	        break;
	      case EnterNotify:
	      case LeaveNotify:
		{
			register XCrossingEvent *ev   = (XCrossingEvent *) re;
			ev->root	= event->u.enterLeave.root;
			ev->window	= event->u.enterLeave.event;
			ev->subwindow	= event->u.enterLeave.child;
			ev->time	= event->u.enterLeave.time;
			ev->x		= event->u.enterLeave.eventX;
			ev->y		= event->u.enterLeave.eventY;
			ev->x_root	= event->u.enterLeave.rootX;
			ev->y_root	= event->u.enterLeave.rootY;
			ev->state	= event->u.enterLeave.state;
			ev->mode	= event->u.enterLeave.mode;
			ev->same_screen = (event->u.enterLeave.flags & 
				ELFlagSameScreen) && True;
			ev->focus	= (event->u.enterLeave.flags &
			  	ELFlagFocus) && True;
			ev->detail	= event->u.u.detail;
		}
		  break;
	      case FocusIn:
	      case FocusOut:
		{
			register XFocusChangeEvent *ev = (XFocusChangeEvent *) re;
			ev->window 	= event->u.focus.window;
			ev->mode	= event->u.focus.mode;
			ev->detail	= event->u.u.detail;
		}
		  break;
	      case KeymapNotify:
		{
			register XKeymapEvent *ev = (XKeymapEvent *) re;
			ev->window	= dpy->current;
			bcopy ((char *)((xKeymapEvent *) event)->map,
			       &ev->key_vector[1], 
			       sizeof (((xKeymapEvent *) event)->map));
		}
		break;
	      case Expose:
		{
			register XExposeEvent *ev = (XExposeEvent *) re;
			ev->window	= event->u.expose.window;
			ev->x		= event->u.expose.x;
			ev->y		= event->u.expose.y;
			ev->width	= event->u.expose.width;
			ev->height	= event->u.expose.height;
			ev->count	= event->u.expose.count;
		}
		break;
	      case GraphicsExpose:
		{
		    register XGraphicsExposeEvent *ev =
			(XGraphicsExposeEvent *) re;
		    ev->drawable	= event->u.graphicsExposure.drawable;
		    ev->x		= event->u.graphicsExposure.x;
		    ev->y		= event->u.graphicsExposure.y;
		    ev->width		= event->u.graphicsExposure.width;
		    ev->height		= event->u.graphicsExposure.height;
		    ev->count		= event->u.graphicsExposure.count;
		    ev->major_code	= event->u.graphicsExposure.majorEvent;
		    ev->minor_code	= event->u.graphicsExposure.minorEvent;
		}
		break;
	      case NoExpose:
		{
		    register XNoExposeEvent *ev = (XNoExposeEvent *) re;
		    ev->drawable	= event->u.noExposure.drawable;
		    ev->major_code	= event->u.noExposure.majorEvent;
		    ev->minor_code	= event->u.noExposure.minorEvent;
		}
		break;
	      case VisibilityNotify:
		{
		    register XVisibilityEvent *ev = (XVisibilityEvent *) re;
		    ev->window		= event->u.visibility.window;
		    ev->state		= event->u.visibility.state;
		}
		break;
	      case CreateNotify:
		{
		    register XCreateWindowEvent *ev =
			 (XCreateWindowEvent *) re;
		    ev->window		= event->u.createNotify.window;
		    ev->parent		= event->u.createNotify.parent;
		    ev->x		= event->u.createNotify.x;
		    ev->y		= event->u.createNotify.y;
		    ev->width		= event->u.createNotify.width;
		    ev->height		= event->u.createNotify.height;
		    ev->border_width	= event->u.createNotify.borderWidth;
		    ev->override_redirect	= event->u.createNotify.override;
		}
		break;
	      case DestroyNotify:
		{
		    register XDestroyWindowEvent *ev =
				(XDestroyWindowEvent *) re;
		    ev->window		= event->u.destroyNotify.window;
		    ev->event		= event->u.destroyNotify.event;
		}
		break;
	      case UnmapNotify:
		{
		    register XUnmapEvent *ev = (XUnmapEvent *) re;
		    ev->window		= event->u.unmapNotify.window;
		    ev->event		= event->u.unmapNotify.event;
		    ev->from_configure	= event->u.unmapNotify.fromConfigure;
		}
		break;
	      case MapNotify:
		{
		    register XMapEvent *ev = (XMapEvent *) re;
		    ev->window		= event->u.mapNotify.window;
		    ev->event		= event->u.mapNotify.event;
		    ev->override_redirect	= event->u.mapNotify.override;
		}
		break;
	      case MapRequest:
		{
		    register XMapRequestEvent *ev = (XMapRequestEvent *) re;
		    ev->window		= event->u.mapRequest.window;
		    ev->parent		= event->u.mapRequest.parent;
		}
		break;
	      case ReparentNotify:
		{
		    register XReparentEvent *ev = (XReparentEvent *) re;
		    ev->event		= event->u.reparent.event;
		    ev->window		= event->u.reparent.window;
		    ev->parent		= event->u.reparent.parent;
		    ev->x		= event->u.reparent.x;
		    ev->y		= event->u.reparent.y;
		    ev->override_redirect	= event->u.reparent.override;
		}
		break;
	      case ConfigureNotify:
		{
		    register XConfigureEvent *ev = (XConfigureEvent *) re;
		    ev->event	= event->u.configureNotify.event;
		    ev->window	= event->u.configureNotify.window;
		    ev->above	= event->u.configureNotify.aboveSibling;
		    ev->x	= event->u.configureNotify.x;
		    ev->y	= event->u.configureNotify.y;
		    ev->width	= event->u.configureNotify.width;
		    ev->height	= event->u.configureNotify.height;
		    ev->border_width  = event->u.configureNotify.borderWidth;
		    ev->override_redirect = event->u.configureNotify.override;
		}
		break;
	      case ConfigureRequest:
		{
		    register XConfigureRequestEvent *ev =
		        (XConfigureRequestEvent *) re;
		    ev->window		= event->u.configureRequest.window;
		    ev->parent		= event->u.configureRequest.parent;
		    ev->above		= event->u.configureRequest.sibling;
		    ev->x		= event->u.configureRequest.x;
		    ev->y		= event->u.configureRequest.y;
		    ev->width		= event->u.configureRequest.width;
		    ev->height		= event->u.configureRequest.height;
		    ev->border_width	= event->u.configureRequest.borderWidth;
		    ev->value_mask	= event->u.configureRequest.valueMask;
		    ev->detail  	= event->u.u.detail;
		}
		break;
	      case GravityNotify:
		{
		    register XGravityEvent *ev = (XGravityEvent *) re;
		    ev->window		= event->u.gravity.window;
		    ev->event		= event->u.gravity.event;
		    ev->x		= event->u.gravity.x;
		    ev->y		= event->u.gravity.y;
		}
		break;
	      case ResizeRequest:
		{
		    register XResizeRequestEvent *ev =
			(XResizeRequestEvent *) re;
		    ev->window		= event->u.resizeRequest.window;
		    ev->width		= event->u.resizeRequest.width;
		    ev->height		= event->u.resizeRequest.height;
		}
		break;
	      case CirculateNotify:
		{
		    register XCirculateEvent *ev = (XCirculateEvent *) re;
		    ev->window		= event->u.circulate.window;
		    ev->event		= event->u.circulate.event;
		    ev->place		= event->u.circulate.place;
		}
		break;
	      case CirculateRequest:
		{
		    register XCirculateRequestEvent *ev =
		        (XCirculateRequestEvent *) re;
		    ev->window		= event->u.circulate.window;
		    ev->parent		= event->u.circulate.event;
		    ev->place		= event->u.circulate.place;
		}
		break;
	      case PropertyNotify:
		{
		    register XPropertyEvent *ev = (XPropertyEvent *) re;
		    ev->window		= event->u.property.window;
		    ev->atom		= event->u.property.atom;
		    ev->time		= event->u.property.time;
		    ev->state		= event->u.property.state;
		}
		break;
	      case SelectionClear:
		{
		    register XSelectionClearEvent *ev =
			 (XSelectionClearEvent *) re;
		    ev->window		= event->u.selectionClear.window;
		    ev->selection	= event->u.selectionClear.atom;
		    ev->time		= event->u.selectionClear.time;
		}
		break;
	      case SelectionRequest:
		{
		    register XSelectionRequestEvent *ev =
		        (XSelectionRequestEvent *) re;
		    ev->owner		= event->u.selectionRequest.owner;
		    ev->requestor	= event->u.selectionRequest.requestor;
		    ev->selection	= event->u.selectionRequest.selection;
		    ev->target		= event->u.selectionRequest.target;
		    ev->property	= event->u.selectionRequest.property;
		    ev->time		= event->u.selectionRequest.time;
		}
		break;
	      case SelectionNotify:
		{
		    register XSelectionEvent *ev = (XSelectionEvent *) re;
		    ev->requestor	= event->u.selectionNotify.requestor;
		    ev->selection	= event->u.selectionNotify.selection;
		    ev->target		= event->u.selectionNotify.target;
		    ev->property	= event->u.selectionNotify.property;
		    ev->time		= event->u.selectionNotify.time;
		}
		break;
	      case ColormapNotify:
		{
		    register XColormapEvent *ev = (XColormapEvent *) re;
		    ev->window		= event->u.colormap.window;
		    ev->colormap	= event->u.colormap.colormap;
		    ev->new		= event->u.colormap.new;
		    ev->state		= event->u.colormap.state;
	        }
		break;
	      case ClientMessage:
		{
		   register int i;
		   register XClientMessageEvent *ev 
		   			= (XClientMessageEvent *) re;
		   ev->window		= event->u.clientMessage.window;
		   ev->format		= event->u.u.detail;
		   switch (ev->format) {
			case 8:	
			   ev->message_type = event->u.clientMessage.u.b.type;
			   for (i = 0; i < 20; i++) 	
			     ev->data.b[i] = event->u.clientMessage.u.b.bytes[i];
			   break;
			case 16:
			   ev->message_type = event->u.clientMessage.u.s.type;
			   ev->data.s[0] = event->u.clientMessage.u.s.shorts0;
			   ev->data.s[1] = event->u.clientMessage.u.s.shorts1;
			   ev->data.s[2] = event->u.clientMessage.u.s.shorts2;
			   ev->data.s[3] = event->u.clientMessage.u.s.shorts3;
			   ev->data.s[4] = event->u.clientMessage.u.s.shorts4;
			   ev->data.s[5] = event->u.clientMessage.u.s.shorts5;
			   ev->data.s[6] = event->u.clientMessage.u.s.shorts6;
			   ev->data.s[7] = event->u.clientMessage.u.s.shorts7;
			   ev->data.s[8] = event->u.clientMessage.u.s.shorts8;
			   ev->data.s[9] = event->u.clientMessage.u.s.shorts9;
			   break;
			case 32:
			   ev->message_type = event->u.clientMessage.u.l.type;
			   ev->data.l[0] = event->u.clientMessage.u.l.longs0;
			   ev->data.l[1] = event->u.clientMessage.u.l.longs1;
			   ev->data.l[2] = event->u.clientMessage.u.l.longs2;
			   ev->data.l[3] = event->u.clientMessage.u.l.longs3;
			   ev->data.l[4] = event->u.clientMessage.u.l.longs4;
			   break;
			default: /* XXX should never occur */
				break;
		    }
	        }
		break;
	      case MappingNotify:
		{
		   register XMappingEvent *ev = (XMappingEvent *)re;
		   ev->first_keycode 	= event->u.mappingNotify.firstKeyCode;
		   ev->request 		= event->u.mappingNotify.request;
		   ev->count 		= event->u.mappingNotify.count;
		}
		break;
	      default:
		return(_XUnknownWireEvent(dpy, re, event));
	}
	return(True);
}


static char *_SysErrorMsg (n)
    int n;
{
    extern char *sys_errlist[];
    extern int sys_nerr;
    char *s = ((n >= 0 && n < sys_nerr) ? sys_errlist[n] : "unknown error");

    return (s ? s : "no such error");
}

/*
 * _XIOError - Default fatal system error reporting routine.  Called when
 * an X internal system error is encountered.
 */
_XIOError (dpy)
	Display *dpy;
{
	(void) fprintf (stderr, 
	 "XIO:  fatal IO error %d (%s) on X server \"%s\"\r\n",
			errno, _SysErrorMsg (errno), DisplayString (dpy));
	(void) fprintf (stderr, 
	 "      after %lu requests (%lu known processed) with %d events remaining.\r\n",
			NextRequest(dpy) - 1, LastKnownRequestProcessed(dpy),
			QLength(dpy));

	if (errno == EPIPE) {
	    (void) fprintf (stderr,
	 "      The connection was probably broken by a server shutdown or KillClient.\r\n");
	}

	exit (1);
}

/*
 * _XError - Default non-fatal error reporting routine.  Called when an
 * X_Error packet is encountered in the input stream.
 */
int _XError (dpy, rep)
    Display *dpy;
    xError *rep;
{
    XErrorEvent event;
    /* 
     * X_Error packet encountered!  We need to unpack the error before
     * giving it to the user.
     */

    event.display = dpy;
    event.type = X_Error;
    event.serial = _SetLastRequestRead(dpy, (xGenericReply *)rep);
    event.resourceid = rep->resourceID;
    event.error_code = rep->errorCode;
    event.request_code = rep->majorCode;
    event.minor_code = rep->minorCode;
    if (_XErrorFunction != NULL) {
      	return ((*_XErrorFunction)(dpy, &event));
      }
    exit(1);
    /*NOTREACHED*/
}
    
int _XPrintDefaultError (dpy, event, fp)
    Display *dpy;
    XErrorEvent *event;
    FILE *fp;
{
    char buffer[BUFSIZ];
    char mesg[BUFSIZ];
    char number[32];
    char *mtype = "XlibMessage";
    XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
    XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
    (void) fprintf(fp, "%s:  %s\n  ", mesg, buffer);
    XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", 
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, event->request_code);
    sprintf(number, "%d", event->request_code);
    XGetErrorDatabaseText(dpy, "XRequest", number, "", 	buffer, BUFSIZ);
    (void) fprintf(fp, " (%s)", buffer);
    fputs("\n  ", fp);
    XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code", 
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, event->minor_code);
    fputs("\n  ", fp);
    XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, event->resourceid);
    fputs("\n  ", fp);
    XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", 
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, event->serial);
    fputs("\n  ", fp);
    XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, dpy->request);
    fputs("\n", fp);
    if (event->error_code == BadImplementation) return 0;
    return 1;
}

int _XDefaultError(dpy, event)
	Display *dpy;
	XErrorEvent *event;
{
    if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0;
    exit(1);
    /*NOTREACHED*/
}

int (*_XIOErrorFunction)() = _XIOError;
int (*_XErrorFunction)() = _XDefaultError;

/*
 * This routine can be used to (cheaply) get some memory within a single
 * Xlib routine for scratch space.  It is reallocated from the same place
 * each time, unless the library needs a large scratch space.
 */
char *_XAllocScratch (dpy, nbytes)
	register Display *dpy;
	unsigned long nbytes;
{
	if (nbytes > dpy->scratch_length) {
	    if (dpy->scratch_buffer != NULL) Xfree (dpy->scratch_buffer);
	    return( dpy->scratch_length = nbytes, 
	    dpy->scratch_buffer = Xmalloc ((unsigned)nbytes) );
	}
	return (dpy->scratch_buffer);
}

/*
 * Given a visual id, find the visual structure for this id on this display.
 */
Visual *_XVIDtoVisual (dpy, id)
	Display *dpy;
	VisualID id;
{
	register int i, j, k;
	register Screen *sp;
	register Depth *dp;
	register Visual *vp;
	for (i = 0; i < dpy->nscreens; i++) {
		sp = &dpy->screens[i];
		for (j = 0; j < sp->ndepths; j++) {
			dp = &sp->depths[j];
			for (k = 0; k < dp->nvisuals; k++) {
				vp = &dp->visuals[k];
				if (vp->visualid == id) return (vp);
			}
		}
	}
	return (NULL);
}

XFree (data)
	char *data;
{
	Xfree (data);
}

#ifdef DataRoutineIsProcedure
void Data (dpy, data, len)
	Display *dpy;
	char *data;
	long len;
{
	if (dpy->bufptr + (len) <= dpy->bufmax) {
		bcopy(data, dpy->bufptr, (int)len);
		dpy->bufptr += ((len) + 3) & ~3;
	} else {
		_XSend(dpy, data, len);
	}
}
#endif /* DataRoutineIsProcedure */


#ifdef WORD64

/*
 * XXX This is a *really* stupid way of doing this.  It should just use 
 * dpy->bufptr directly, taking into account where in the word it is.
 */

/*
 * Data16 - Place 16 bit data in the buffer.
 *
 * "dpy" is a pointer to a Display.
 * "data" is a pointer to the data.
 * "len" is the length in bytes of the data.
 */

static doData16(dpy, data, len, packbuffer)
    register Display *dpy;
    short *data;
    unsigned len;
    char *packbuffer;
{
    long *lp,*lpack;
    long i, nwords,bits;
    long mask16 = 0x000000000000ffff;

        lp = (long *)data;
        lpack = (long *)packbuffer;
        *lpack = 0;

/*  nwords is the number of 16 bit values to be packed,
 *  the low order 16 bits of each word will be packed
 *  into 64 bit words
 */
        nwords = len >> 1;
        bits = 48;

        for(i=0;i<nwords;i++){
           *lpack ^= (*lp & mask16) << bits;
           bits -= 16 ;
           lp++;
           if(bits < 0){
               lpack++;
               *lpack = 0;
               bits = 48;
           }
        }
        Data(dpy, packbuffer, len);
}

Data16 (dpy, data, len)
    Display *dpy;
    short *data;
    unsigned len;
{
    char packbuffer[PACKBUFFERSIZE];
    unsigned nwords = (PACKBUFFERSIZE >> 1);	/* bytes to CARD16 */

    for (; len > nwords; len -= nwords, data += nwords) {
	doData16 (dpy, data, nwords, packbuffer);
    }
    doData16 (dpy, data, len, packbuffer);
}

/*
 * Data32 - Place 32 bit data in the buffer.
 *
 * "dpy" is a pointer to a Display.
 * "data" is a pointer to the data.
 * "len" is the length in bytes of the data.
 */

static doData32 (dpy, data, len, packbuffer)
    register Display *dpy;
    long *data;
    unsigned len;
    char *packbuffer;
{
    long *lp,*lpack;
    long i,bits,nwords;
    long mask32 = 0x00000000ffffffff;

        lpack = (long *) packbuffer;
        lp = data;

        *lpack = 0;

/*  nwords is the number of 32 bit values to be packed
 *  the low order 32 bits of each word will be packed
 *  into 64 bit words
 */
        nwords = len >> 2;
        bits = 32;

        for(i=0;i<nwords;i++){
           *lpack ^= (*lp & mask32) << bits;
           bits = bits ^32;
           lp++;
           if(bits){
              lpack++;
              *lpack = 0;
           }
        }
        Data(dpy, packbuffer, len);
}

Data32 (dpy, data, len)
    Display *dpy;
    short *data;
    unsigned len;
{
    char packbuffer[PACKBUFFERSIZE];
    unsigned nwords = (PACKBUFFERSIZE >> 2);	/* bytes to CARD32 */

    for (; len > nwords; len -= nwords, data += nwords) {
	doData32 (dpy, data, nwords, packbuffer);
    }
    doData32 (dpy, data, len, packbuffer);
}

#endif /* WORD64 */



/*
 * _XFreeQ - free the queue of events, called by XCloseDisplay when there are
 * no more displays left on the display list
 */

void _XFreeQ ()
{
    register _XQEvent *qelt = _qfree;
  
    while (qelt) {
	register _XQEvent *qnext = qelt->next;
	Xfree (qelt);
	qelt = qnext;
    }
    _qfree = NULL;
    return;
}