/* * cslibint.c -- low level I/O * * (c) Copyright 1993-1994 Adobe Systems Incorporated. * All rights reserved. * * Permission to use, copy, modify, distribute, and sublicense this software * and its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notices appear in all copies and that * both those copyright notices and this permission notice appear in * supporting documentation and that the name of Adobe Systems Incorporated * not be used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. No trademark license * to use the Adobe trademarks is hereby granted. If the Adobe trademark * "Display PostScript"(tm) is used to describe this software, its * functionality or for any other purpose, such use shall be limited to a * statement that this software works in conjunction with the Display * PostScript system. Proper trademark attribution to reflect Adobe's * ownership of the trademark shall be given whenever any such reference to * the Display PostScript system is made. * * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON- INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE. * * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems * Incorporated which may be registered in certain jurisdictions * * Portions Copyright 1985, 1986, 1987 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * Author: Adobe Systems Incorporated and MIT X Consortium */ /* $XFree86: xc/lib/dps/cslibint.c,v 1.4 2000/05/18 23:46:12 dawes Exp $ */ /* * 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 #include #include "Xlibnet.h" #include #include "dpsassert.h" #include "cslibint.h" static void _EatData32 (Display *dpy, unsigned long n); /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX * systems are broken and return EWOULDBLOCK when they should return EAGAIN */ #if defined(EAGAIN) && defined(EWOULDBLOCK) #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK) #else #ifdef EAGAIN #define ETEST(err) (err == EAGAIN) #else #define ETEST(err) (err == EWOULDBLOCK) #endif #endif #ifdef LACHMAN #ifdef EMSGSIZE #undef EMSGSIZE #endif #define EMSGSIZE ERANGE #endif #if defined(SVR4) && defined(sun) #define SUNSYSV 1 #endif /* * 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. */ extern _XQEvent *_qfree; 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 }; /* * N_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. */ void N_XFlush (Display *dpy) { register long size, todo; register int write_stat; register char *bufindex; if (!dpy) return; if (dpy->flags & XlibDisplayIOError) return; 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; } else if (ETEST(errno)) { N_XWaitForWritable(dpy); #ifdef SUNSYSV } else if (errno == 0) { N_XWaitForWritable(dpy); #endif #ifdef EMSGSIZE } else if (errno == EMSGSIZE) { if (todo > 1) todo >>= 1; else N_XWaitForWritable(dpy); #endif } else if (errno != EINTR) { /* Write failed! */ /* errno set by write system call. */ _XIOError(dpy); } } dpy->last_req = (char *)&_dummy_request; } #ifdef NEEDFORNX int _XEventsQueued (Display *dpy, int mode) { register int len; int pend; char buf[BUFSIZE]; register xReply *rep; if (mode == QueuedAfterFlush) { _XFlush(dpy); if (dpy->qlen) return(dpy->qlen); } if (dpy->flags & XlibDisplayIOError) return(dpy->qlen); if (BytesReadable(dpy->fd, (char *) &pend) < 0) _XIOError(dpy); #ifdef XCONN_CHECK_FREQ /* This is a crock, required because FIONREAD or equivalent is * not guaranteed to detect a broken connection. */ if (!pend && !dpy->qlen && ++dpy->conn_checker >= XCONN_CHECK_FREQ) { unsigned long r_mask[MSKCNT]; static struct timeval zero_time; dpy->conn_checker = 0; CLEARBITS(r_mask); BITSET(r_mask, dpy->fd); if (pend = select(dpy->fd + 1, (int *)r_mask, NULL, NULL, &zero_time)) { if (pend > 0) { if (BytesReadable(dpy->fd, (char *) &pend) < 0) _XIOError(dpy); /* we should not get zero, if we do, force a read */ if (!pend) pend = SIZEOF(xReply); } else if (pend < 0 && errno != EINTR) _XIOError(dpy); } } #endif /* XCONN_CHECK_FREQ */ if (!(len = pend)) return(dpy->qlen); /* _XFlush can enqueue events */ /* Force a read if there is not enough data. Otherwise, * a select() loop at a higher-level will spin undesirably, * and we've seen at least one OS that appears to not update * the result from FIONREAD once it has returned nonzero. */ if (len < SIZEOF(xReply)) len = SIZEOF(xReply); else if (len > BUFSIZE) len = BUFSIZE; len /= SIZEOF(xReply); pend = len * SIZEOF(xReply); #ifdef XCONN_CHECK_FREQ dpy->conn_checker = 0; #endif _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 */ void _XReadEvents(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) _XIOError(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); } #endif /* NEEDFORNX */ /* * N_XRead - Read bytes from the socket taking into account incomplete * reads. This routine may have to be reworked if int < long. */ int N_XRead (Display *dpy, char *data, long size) { register long bytes_read; if (!dpy) return 0; if ((dpy->flags & XlibDisplayIOError) || size == 0) return 0; errno = 0; while ((bytes_read = ReadFromServer(dpy->fd, data, (int)size)) != size) { if (bytes_read > 0) { size -= bytes_read; data += bytes_read; } else if (ETEST(errno)) { N_XWaitForReadable(dpy); errno = 0; } #ifdef SUNSYSV else if (errno == 0) { N_XWaitForReadable(dpy); } #endif else if (bytes_read == 0) { /* Read failed because of end of file! */ errno = EPIPE; _XIOError(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) _XIOError(dpy); } } return 0; } #ifdef WORD64 /* * XXX This is a *really* stupid way of doing this.... * PACKBUFFERSIZE must be a multiple of 4. */ #define PACKBUFFERSIZE 4096 /* * _XRead32 - Read bytes from the socket unpacking each 32 bits * into a long (64 bits on a CRAY computer). * */ static void _doXRead32 (Display *dpy, long *data, long size, 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> bits; bits = bits ^32; if(bits){ lpack++; } } } void _XRead32 (Display *dpy, long *data, long len) { char packbuffer[PACKBUFFERSIZE]; unsigned nunits = PACKBUFFERSIZE >> 2; for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) { _doXRead32 (dpy, data, PACKBUFFERSIZE, packbuffer); } if (len) _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 void _doXRead16 (Display *dpy, short *data, 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> bits; bits -= 16; if(bits < 0){ lpack++; bits = 48; } } } void _XRead16 (Display *dpy, short *data, long len) { char packbuffer[PACKBUFFERSIZE]; unsigned nunits = PACKBUFFERSIZE >> 1; for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) { _doXRead16 (dpy, data, PACKBUFFERSIZE, packbuffer); } if (len) _doXRead16 (dpy, data, len, packbuffer); } void _XRead16Pad (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 */ /* * N_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. */ void N_XReadPad (Display *dpy, char *data, long size) { register long bytes_read; struct iovec iov[2]; char pad[3]; if (!dpy) return; if ((dpy->flags & XlibDisplayIOError) || 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 = (char *)iov[1].iov_base - iov[0].iov_len; iov[0].iov_len = 0; } else iov[0].iov_base = (char *)iov[0].iov_base + bytes_read; } else if (ETEST(errno)) { N_XWaitForReadable(dpy); errno = 0; } #ifdef SUNSYSV else if (errno == 0) { N_XWaitForReadable(dpy); } #endif else if (bytes_read == 0) { /* Read failed because of end of file! */ errno = EPIPE; _XIOError(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) _XIOError(dpy); } } } /* * N_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; */ void N_XSend (Display *dpy, _Xconst char *data, 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 dpybufsize = (dpy->bufptr - dpy->buffer); long padsize = padlength[size & 3]; long total = dpybufsize + size + padsize; long todo = total; if (dpy->flags & XlibDisplayIOError) return; /* * There are 3 pieces that may need to be written out: * * o whatever is in the display buffer * o the data passed in by the user * o any padding needed to 32bit align the whole mess * * This loop looks at all 3 pieces each time through. It uses skip * to figure out whether or not a given piece is needed. */ while (total) { long before = skip; /* amount of whole thing written */ long remain = todo; /* amount to try this time, <= total */ 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. This * translates to: * * how much of this piece is new? * if more new then we are trying this time, clamp * if nothing new * then bump down amount already written, for next piece * else put new stuff in iovec, will need all of next piece * * Note that todo had better be at least 1 or else we'll end up * writing 0 iovecs. */ #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, dpybufsize) InsertIOV ((char *)data, size) InsertIOV (pad, padsize) errno = 0; if ((len = WritevToServer(dpy->fd, iov, i)) >= 0) { skip += len; total -= len; todo = total; } else if (ETEST(errno)) { N_XWaitForWritable(dpy); #ifdef SUNSYSV } else if (errno == 0) { N_XWaitForWritable(dpy); #endif #ifdef EMSGSIZE } else if (errno == EMSGSIZE) { if (todo > 1) todo >>= 1; else N_XWaitForWritable(dpy); #endif } else if (errno != EINTR) { _XIOError(dpy); } } dpy->bufptr = dpy->buffer; dpy->last_req = (char *) & _dummy_request; return; } #ifdef NEEDFORNX /* * _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(Display *dpy) { XID id; id = dpy->resource_id << dpy->resource_shift; if (id <= dpy->resource_mask) { dpy->resource_id++; return (dpy->resource_base + id); } if (id != 0x10000000) { (void) fprintf(stderr, "Xlib: resource ID allocation space exhausted!\n"); id = 0x10000000; dpy->resource_id = id >> dpy->resource_shift; } return id; } /* * 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. */ unsigned long _XSetLastRequestRead(Display *dpy, 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); } #endif /* NEEDFORNX */ /* * N_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 N_XReply ( Display *dpy, xReply *rep, int extra, /* number of 32-bit words expected after the reply */ Bool discard) /* should I discard data following "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; if (dpy->flags & XlibDisplayIOError) return (0); N_XFlush(dpy); while (1) { N_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) _XSetLastRequestRead(dpy, &rep->generic); if (extra == 0) { if (discard && (rep->generic.length > 0)) /* unexpectedly long reply! */ _EatData32 (dpy, rep->generic.length); return (1); } if ((unsigned) extra == rep->generic.length) { /* * Read the extra data into storage immediately following * the GenericReply structure. */ N_XRead (dpy, (char *) (NEXTPTR(rep,xReply)), ((long)extra) << 2); return (1); } if ((unsigned) extra < rep->generic.length) { /* Actual reply is longer than "extra" */ N_XRead (dpy, (char *) (NEXTPTR(rep,xReply)), ((long)extra) << 2); if (discard) _EatData32 (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... */ N_XRead (dpy, (char *) (NEXTPTR(rep,xReply)), ((long) rep->generic.length) << 2); _XIOError (dpy); return (0); case X_Error: { register _XExtension *ext; register Bool ret = False; int ret_code; xError *err = (xError *) rep; unsigned long serial; serial = _XSetLastRequestRead(dpy, (xGenericReply *)rep); /* * we better see if there is an extension who may * want to suppress the error. */ for (ext = dpy->ext_procs; !ret && ext; ext = ext->next) { if (ext->error) ret = (*ext->error)(dpy, err, &ext->codes, &ret_code); } if (!ret) { _XError(dpy, err); ret_code = 0; } if (serial == cur_request) return(ret_code); } break; default: /* There should never be any events on this connection! */ DPSFatalProc(NULL, "N_XReply read bogus X event"); break; } } } /* Read and discard "n" 8-bit bytes of data */ static void N_XEatData (Display *dpy, unsigned long n) { #define SCRATCHSIZE 2048 char buf[SCRATCHSIZE]; while (n > 0) { register long bytes_read = (n > SCRATCHSIZE) ? SCRATCHSIZE : n; N_XRead (dpy, buf, bytes_read); n -= bytes_read; } #undef SCRATCHSIZE } /* Read and discard "n" 32-bit words. */ static void _EatData32 (Display *dpy, unsigned long n) { N_XEatData (dpy, n << 2); } #ifdef NEEDFORNX /* * _XEnq - Place event packets on the display's queue. * note that no squishing of move events in V11, since there * is pointer motion hints.... */ void _XEnq (Display *dpy, 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; _XIOError(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 separate file in that often not needed. */ #endif /* NEEDFORNX */ /*ARGSUSED*/ Bool N_XUnknownWireEvent( Display *dpy, /* pointer to display structure */ XEvent *re, /* pointer to where event should be reformatted */ xEvent *event) /* wire protocol event */ { char mbuf[256]; sprintf(mbuf, "NX: unhandled wire event %d, agent = %lx", re->type, (long)dpy); DPSWarnProc(NULL, mbuf); return(False); } /*ARGSUSED*/ Status N_XUnknownNativeEvent( Display *dpy, /* pointer to display structure */ XEvent *re, /* pointer to where event should be reformatted */ xEvent *event) /* wire protocol event */ { char mbuf[256]; sprintf(mbuf, "NX: unhandled native event %d, agent = %lx", re->type, (long)dpy); DPSWarnProc(NULL, mbuf); return(0); } #ifdef NEEDFORNX /* * reformat a wire event into an XEvent structure of the right type. */ Bool _XWireToEvent( Display *dpy, /* pointer to display structure */ XEvent *re, /* pointer to where event should be reformatted */ xEvent *event) /* wire protocol event */ { re->type = event->u.u.type & 0x7f; ((XAnyEvent *)re)->serial = _XSetLastRequestRead(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 = cvtINT16toInt(event->u.keyButtonPointer.eventX); ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY); ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX); ev->y_root = cvtINT16toInt(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 = cvtINT16toInt(event->u.keyButtonPointer.eventX); ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY); ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX); ev->y_root = cvtINT16toInt(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 = cvtINT16toInt(event->u.keyButtonPointer.eventX); ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY); ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX); ev->y_root = cvtINT16toInt(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 = cvtINT16toInt(event->u.enterLeave.eventX); ev->y = cvtINT16toInt(event->u.enterLeave.eventY); ev->x_root = cvtINT16toInt(event->u.enterLeave.rootX); ev->y_root = cvtINT16toInt(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 = cvtINT16toInt(event->u.createNotify.x); ev->y = cvtINT16toInt(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 = cvtINT16toInt(event->u.reparent.x); ev->y = cvtINT16toInt(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 = cvtINT16toInt(event->u.configureNotify.x); ev->y = cvtINT16toInt(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 = cvtINT16toInt(event->u.configureRequest.x); ev->y = cvtINT16toInt(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 = cvtINT16toInt(event->u.gravity.x); ev->y = cvtINT16toInt(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] = cvtINT16toShort(event->u.clientMessage.u.s.shorts0); ev->data.s[1] = cvtINT16toShort(event->u.clientMessage.u.s.shorts1); ev->data.s[2] = cvtINT16toShort(event->u.clientMessage.u.s.shorts2); ev->data.s[3] = cvtINT16toShort(event->u.clientMessage.u.s.shorts3); ev->data.s[4] = cvtINT16toShort(event->u.clientMessage.u.s.shorts4); ev->data.s[5] = cvtINT16toShort(event->u.clientMessage.u.s.shorts5); ev->data.s[6] = cvtINT16toShort(event->u.clientMessage.u.s.shorts6); ev->data.s[7] = cvtINT16toShort(event->u.clientMessage.u.s.shorts7); ev->data.s[8] = cvtINT16toShort(event->u.clientMessage.u.s.shorts8); ev->data.s[9] = cvtINT16toShort(event->u.clientMessage.u.s.shorts9); break; case 32: ev->message_type = event->u.clientMessage.u.l.type; ev->data.l[0] = cvtINT32toLong(event->u.clientMessage.u.l.longs0); ev->data.l[1] = cvtINT32toLong(event->u.clientMessage.u.l.longs1); ev->data.l[2] = cvtINT32toLong(event->u.clientMessage.u.l.longs2); ev->data.l[3] = cvtINT32toLong(event->u.clientMessage.u.l.longs3); ev->data.l[4] = cvtINT32toLong(event->u.clientMessage.u.l.longs4); break; default: /* XXX should never occur */ break; } } break; case MappingNotify: { register XMappingEvent *ev = (XMappingEvent *)re; ev->window = 0; 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); } #ifndef USL_SHARELIB static char *_SysErrorMsg (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"); } #endif /* USL sharedlibs in don't define for SVR3.2 */ /* * _XDefaultIOError - Default fatal system error reporting routine. Called * when an X internal system error is encountered. */ _XDefaultIOError (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); } static int _XPrintDefaultError (Display *dpy, XErrorEvent *event, FILE *fp) { char buffer[BUFSIZ]; char mesg[BUFSIZ]; char number[32]; char *mtype = "XlibMessage"; register _XExtension *ext = (_XExtension *)NULL; _XExtension *bext = (_XExtension *)NULL; 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); if (event->request_code < 128) { sprintf(number, "%d", event->request_code); XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ); } else { for (ext = dpy->ext_procs; ext && (ext->codes.major_opcode != event->request_code); ext = ext->next) ; if (ext) strcpy(buffer, ext->name); else buffer[0] = '\0'; } (void) fprintf(fp, " (%s)\n", buffer); if (event->request_code >= 128) { XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d", mesg, BUFSIZ); fputs(" ", fp); (void) fprintf(fp, mesg, event->minor_code); if (ext) { sprintf(mesg, "%s.%d", ext->name, event->minor_code); XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ); (void) fprintf(fp, " (%s)", buffer); } fputs("\n", fp); } if (event->error_code >= 128) { /* kludge, try to find the extension that caused it */ buffer[0] = '\0'; for (ext = dpy->ext_procs; ext; ext = ext->next) { if (ext->error_string) (*ext->error_string)(dpy, event->error_code, &ext->codes, buffer, BUFSIZ); if (buffer[0]) { bext = ext; break; } if (ext->codes.first_error && ext->codes.first_error < event->error_code && (!bext || ext->codes.first_error > bext->codes.first_error)) bext = ext; } if (bext) sprintf(buffer, "%s.%d", bext->name, event->error_code - bext->codes.first_error); else strcpy(buffer, "Value"); XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ); if (mesg[0]) { fputs(" ", fp); (void) fprintf(fp, mesg, event->resourceid); fputs("\n", fp); } /* let extensions try to print the values */ for (ext = dpy->ext_procs; ext; ext = ext->next) { if (ext->error_values) (*ext->error_values)(dpy, event, fp); } } else if ((event->error_code == BadWindow) || (event->error_code == BadPixmap) || (event->error_code == BadCursor) || (event->error_code == BadFont) || (event->error_code == BadDrawable) || (event->error_code == BadColor) || (event->error_code == BadGC) || (event->error_code == BadIDChoice) || (event->error_code == BadValue) || (event->error_code == BadAtom)) { if (event->error_code == BadValue) XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x", mesg, BUFSIZ); else if (event->error_code == BadAtom) XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x", mesg, BUFSIZ); else XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x", mesg, BUFSIZ); fputs(" ", fp); (void) fprintf(fp, mesg, event->resourceid); fputs("\n", fp); } XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", mesg, BUFSIZ); fputs(" ", fp); (void) fprintf(fp, mesg, event->serial); XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d", mesg, BUFSIZ); fputs("\n ", fp); (void) fprintf(fp, mesg, dpy->request); fputs("\n", fp); if (event->error_code == BadImplementation) return 0; return 1; } int _XDefaultError(Display *dpy, XErrorEvent *event) { if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0; exit(1); /*NOTREACHED*/ } /*ARGSUSED*/ Bool _XDefaultWireError(Display *display, XErrorEvent *he, xError *we) { return True; } /* * _XError - prepare to upcall user protocol error handler */ int _XError (Display *dpy, xError *rep) { /* * X_Error packet encountered! We need to unpack the error before * giving it to the user. */ XEvent event; /* make it a large event */ event.xerror.display = dpy; event.xerror.type = X_Error; event.xerror.serial = _XSetLastRequestRead(dpy, (xGenericReply *)rep); event.xerror.resourceid = rep->resourceID; event.xerror.error_code = rep->errorCode; event.xerror.request_code = rep->majorCode; event.xerror.minor_code = rep->minorCode; if (dpy->error_vec && !(*dpy->error_vec[rep->errorCode])(dpy, &event.xerror, rep)) return 0; if (_XErrorFunction != NULL) { return ((*_XErrorFunction)(dpy, &event)); /* upcall */ } else { return _XDefaultError(dpy, &event); } } /* * _XIOError - call user connection error handler and exit */ int _XIOError (Display *dpy) { dpy->flags |= XlibDisplayIOError; if (_XIOErrorFunction != NULL) (*_XIOErrorFunction)(dpy); else _XDefaultIOError(dpy); exit (1); } /* * 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 (Display *dpy, unsigned long nbytes) { if (nbytes > dpy->scratch_length) { if (dpy->scratch_buffer) Xfree (dpy->scratch_buffer); if (dpy->scratch_buffer = Xmalloc((unsigned) nbytes)) dpy->scratch_length = nbytes; else dpy->scratch_length = 0; } return (dpy->scratch_buffer); } /* * Given a visual id, find the visual structure for this id on this display. */ Visual *_XVIDtoVisual (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]; /* if nvisuals == 0 then visuals will be NULL */ for (k = 0; k < dp->nvisuals; k++) { vp = &dp->visuals[k]; if (vp->visualid == id) return (vp); } } } return (NULL); } void XFree (void *data) { Xfree (data); } #ifdef _XNEEDBCOPYFUNC void _Xbcopy(char *b1, char *b2, length) { if (b1 < b2) { b2 += length; b1 += length; while (length--) *--b2 = *--b1; } else { while (length--) *b2++ = *b1++; } } #endif #endif /* NEEDFORNX */ void NXProcData (Display *dpy, char *data, long len) { if (dpy->bufptr + (len) <= dpy->bufmax) { bcopy(data, dpy->bufptr, (int)len); dpy->bufptr += ((len) + 3) & ~3; } else { N_XSend(dpy, data, len); } } #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 void doData16(Display *dpy, short *data, unsigned len, char *packbuffer) { long *lp,*lpack; long i, nwords,bits; long mask16 = 0x000000000000ffff; lp = (long *)data; lpack = (long *)packbuffer; /* 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> 1; for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) { doData16 (dpy, data, PACKBUFFERSIZE, packbuffer); } if (len) 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 (Display *dpy, long *data, unsigned len, char *packbuffer) { long *lp,*lpack; long i,bits,nwords; long mask32 = 0x00000000ffffffff; lpack = (long *) packbuffer; lp = data; /* 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> 2; for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) { doData32 (dpy, data, PACKBUFFERSIZE, packbuffer); } if (len) doData32 (dpy, data, len, packbuffer); } #endif /* WORD64 */ #ifdef NEEDFORNX /* * _XFreeQ - free the queue of events, called by XCloseDisplay */ void _XFreeQ (void) { register _XQEvent *qelt = _qfree; while (qelt) { register _XQEvent *qnxt = qelt->next; Xfree ((char *) qelt); qelt = qnxt; } _qfree = NULL; return; } #endif /* NEEDFORNX */ /* Make sure this produces the same string as DefineLocal/DefineSelf in xdm. * Otherwise, Xau will not be able to find your cookies in the Xauthority file. * * Note: POSIX says that the ``nodename'' member of utsname does _not_ have * to have sufficient information for interfacing to the network, * and so, you may be better off using gethostname (if it exists). */ #if (defined(_POSIX_SOURCE) && !defined(AIXV3)) || defined(hpux) || defined(USG) || defined(SVR4) #define NEED_UTSNAME #include #endif /* * N_XGetHostname - similar to gethostname but allows special processing. */ int N_XGetHostname (char *buf, int maxlen) { int len; #ifdef NEED_UTSNAME struct utsname name; uname (&name); len = strlen (name.nodename); if (len >= maxlen) len = maxlen - 1; strncpy (buf, name.nodename, len); buf[len] = '\0'; #else buf[0] = '\0'; (void) gethostname (buf, maxlen); buf [maxlen - 1] = '\0'; len = strlen(buf); #endif /* NEED_UTSNAME */ return len; } #ifdef NEEDFORNX /* * _XScreenOfWindow - get the Screen of a given window */ Screen *_XScreenOfWindow (Display *dpy, Window w) { register int i; Window root; int x, y; /* dummy variables */ unsigned int width, height, bw, depth; /* dummy variables */ if (XGetGeometry (dpy, w, &root, &x, &y, &width, &height, &bw, &depth) == False) { return None; } for (i = 0; i < ScreenCount (dpy); i++) { /* find root from list */ if (root == RootWindow (dpy, i)) { return ScreenOfDisplay (dpy, i); } } return NULL; } #endif /* NEEDFORNX */ #if (MSKCNT > 4) /* * This is a macro if MSKCNT <= 4 */ int N_XANYSET(unsigned long *src) { int i; for (i=0; i int _XReadV (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)); } int _XWriteV (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 */ #if defined(SYSV) && defined(i386) && !defined(STREAMSCONN) /* * SYSV/386 does not have readv so we emulate */ #include int _XReadV (int fd, struct iovec *iov, int iovcnt) { int i, len, total; char *base; errno = 0; for (i=0, total=0; iiov_len; base = iov->iov_base; while (len > 0) { register int nbytes; nbytes = read(fd, base, len); if (nbytes < 0 && total == 0) return -1; if (nbytes <= 0) return total; errno = 0; len -= nbytes; total += nbytes; base += nbytes; } } return total; } #endif /* SYSV && i386 && !STREAMSCONN */ #ifdef STREAMSCONN /* * Copyright 1988, 1989 AT&T, Inc. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of AT&T not be used in advertising * or publicity pertaining to distribution of the software without specific, * written prior permission. AT&T makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL AT&T * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* iovec.c (C source file) Acc: 575557389 Mon Mar 28 08:03:09 1988 Mod: 575557397 Mon Mar 28 08:03:17 1988 Sta: 575557397 Mon Mar 28 08:03:17 1988 Owner: 2011 Group: 1985 Permissions: 664 */ /* START USER STAMP AREA */ /* END USER STAMP AREA */ extern char _XsTypeofStream[]; extern Xstream _XsStream[]; #define MAX_WORKAREA 4096 static char workarea[MAX_WORKAREA]; int _XReadV (int fd, struct iovec v[], int n) { int i, rc, len, size = 0; char * buf = workarea; char * p; if (n <= 0 || n > 16) { errno = EINVAL; return (-1); } for (i = 0; i < n; ++i) { if ((len = v[i].iov_len) < 0 || v[i].iov_base == NULL) { errno = EINVAL; return (-1); } size += len; } if ((size > MAX_WORKAREA) && ((buf = malloc (size)) == NULL)) { errno = EINVAL; return (-1); } if((rc = (*_XsStream[_XsTypeOfStream[fd]].ReadFromStream)(fd, buf, size, BUFFERING))> 0) { for (i = 0, p = buf; i < n; ++i) { memcpy (v[i].iov_base, p, len = v[i].iov_len); p += len; } } if (size > MAX_WORKAREA) free (buf); return (rc); } int _XWriteV (int fd, struct iovec v[], int n) { int i, rc, len, size = 0; char * buf = workarea; char * p; if (n <= 0 || n > 16) { errno = EINVAL; return (-1); } for (i = 0; i < n; ++i) { if ((len = v[i].iov_len) < 0 || v[i].iov_base == NULL) { errno = EINVAL; return (-1); } size += len; } if ((size > MAX_WORKAREA) && ((buf = malloc (size)) == NULL)) { errno = EINVAL; return (-1); } for (i = 0, p = buf; i < n; ++i) { memcpy (p, v[i].iov_base, len = v[i].iov_len); p += len; } rc = (*_XsStream[_XsTypeOfStream[fd]].WriteToStream)(fd, buf, size); if (size > MAX_WORKAREA) free (buf); return (rc); } #endif /* STREAMSCONN */ #endif /* NEEDFORNX */