📄 xlibint.c
字号:
/* * $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];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -