#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include "FSlibint.h"
#include <X11/Xos.h>
static void _EatData32 ( FSServer *svr, unsigned long n );
static char * _SysErrorMsg ( int n );
#ifdef WIN32
#define ETEST() (WSAGetLastError() == WSAEWOULDBLOCK)
#else
#if defined(EAGAIN) && defined(EWOULDBLOCK)
#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK)
#else
#ifdef EAGAIN
#define ETEST() (errno == EAGAIN)
#else
#define ETEST() (errno == EWOULDBLOCK)
#endif
#endif
#endif
#ifdef WIN32
#define ECHECK(err) (WSAGetLastError() == err)
#define ESET(val) WSASetLastError(val)
#else
#ifdef ISC
#define ECHECK(err) ((errno == err) || ETEST())
#else
#define ECHECK(err) (errno == err)
#endif
#define ESET(val) errno = val
#endif
_FSQEvent *_FSqfree = NULL;
static int padlength[4] = {0, 3, 2, 1};
static fsReq _dummy_request = {
0, 0, 0
};
void
_FSFlush(svr)
register FSServer *svr;
{
register long size,
todo;
register int write_stat;
register char *bufindex;
size = todo = svr->bufptr - svr->buffer;
bufindex = svr->bufptr = svr->buffer;
while (size) {
ESET(0);
write_stat = _FSTransWrite(svr->trans_conn, bufindex, (int) todo);
if (write_stat >= 0) {
size -= write_stat;
todo = size;
bufindex += write_stat;
} else if (ETEST()) {
_FSWaitForWritable(svr);
#ifdef SUNSYSV
} else if (ECHECK(0)) {
_FSWaitForWritable(svr);
#endif
#ifdef EMSGSIZE
} else if (ECHECK(EMSGSIZE)) {
if (todo > 1)
todo >>= 1;
else
_FSWaitForWritable(svr);
#endif
} else {
(*_FSIOErrorFunction) (svr);
}
}
svr->last_req = (char *) &_dummy_request;
}
int
_FSEventsQueued(svr, mode)
register FSServer *svr;
int mode;
{
register BytesReadable_t len;
BytesReadable_t pend;
char buf[BUFSIZE];
register fsReply *rep;
if (mode == QueuedAfterFlush) {
_FSFlush(svr);
if (svr->qlen)
return (svr->qlen);
}
if (_FSTransBytesReadable(svr->trans_conn, &pend) < 0)
(*_FSIOErrorFunction) (svr);
if ((len = pend) < SIZEOF(fsReply))
return (svr->qlen);
else if (len > BUFSIZE)
len = BUFSIZE;
len /= SIZEOF(fsReply);
pend = len * SIZEOF(fsReply);
_FSRead(svr, buf, (long) pend);
STARTITERATE(rep, fsReply, buf, (len > 0), len--) {
if (rep->generic.type == FS_Error)
_FSError(svr, (fsError *) rep);
else
_FSEnq(svr, (fsEvent *) rep);
}
ENDITERATE
return (svr->qlen);
}
void
_FSReadEvents(svr)
register FSServer *svr;
{
char buf[BUFSIZE];
BytesReadable_t pend_not_register;
register BytesReadable_t pend;
register fsEvent *ev;
Bool not_yet_flushed = True;
do {
if (_FSTransBytesReadable(svr->trans_conn, &pend_not_register) < 0)
(*_FSIOErrorFunction) (svr);
pend = pend_not_register;
if (pend < SIZEOF(fsEvent)) {
pend = SIZEOF(fsEvent);
if (not_yet_flushed) {
int qlen = svr->qlen;
_FSFlush(svr);
if (qlen != svr->qlen)
return;
not_yet_flushed = False;
}
}
if (pend > BUFSIZE)
pend = BUFSIZE;
pend = (pend / SIZEOF(fsEvent)) * SIZEOF(fsEvent);
_FSRead(svr, buf, (long)pend);
STARTITERATE(ev, fsEvent, buf, (pend > 0),
pend -= SIZEOF(fsEvent)) {
if (ev->type == FS_Error)
_FSError(svr, (fsError *) ev);
else
_FSEnq(svr, ev);
}
ENDITERATE
} while (svr->head == NULL);
}
void
_FSRead(svr, data, size)
register FSServer *svr;
register char *data;
register long size;
{
register long bytes_read;
#if defined(SVR4) && defined(i386)
int num_failed_reads = 0;
#endif
if (size == 0)
return;
ESET(0);
while ((bytes_read = _FSTransRead(svr->trans_conn, data, (int) size))
!= size) {
if (bytes_read > 0) {
size -= bytes_read;
data += bytes_read;
#if defined(SVR4) && defined(i386)
num_failed_reads = 0;
#endif
}
else if (ETEST()) {
_FSWaitForReadable(svr);
#if defined(SVR4) && defined(i386)
num_failed_reads++;
if (num_failed_reads > 1) {
ESET(EPIPE);
(*_FSIOErrorFunction) (svr);
}
#endif
ESET(0);
}
#ifdef SUNSYSV
else if (ECHECK(0)) {
_FSWaitForReadable(svr);
}
#endif
else if (bytes_read == 0) {
ESET(EPIPE);
(*_FSIOErrorFunction) (svr);
} else {
if (!ECHECK(EINTR))
(*_FSIOErrorFunction) (svr);
#if defined(SVR4) && defined(i386)
else
num_failed_reads = 0;
#endif
}
}
}
#ifdef WORD64
#define PACKBUFFERSIZE 4096
static void
_doFSRead32(svr, data, size, packbuffer)
register FSServer *svr;
register long *data;
register long size;
register char *packbuffer;
{
long *lpack,
*lp;
long mask32 = 0x00000000ffffffff;
long maskw,
nwords,
i,
bits;
_FSReadPad(svr, 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++;
}
}
}
void
_FSRead32(svr, data, len)
FSServer *svr;
long *data;
long len;
{
char packbuffer[PACKBUFFERSIZE];
unsigned nwords = (PACKBUFFERSIZE >> 2);
for (; len > nwords; len -= nwords, data += nwords) {
_doFSRead32(svr, data, nwords, packbuffer);
}
_doFSRead32(svr, data, len, packbuffer);
}
static void
_doFSRead16(svr, data, size, packbuffer)
register FSServer *svr;
register short *data;
register long size;
char *packbuffer;
{
long *lpack,
*lp;
long mask16 = 0x000000000000ffff;
long maskw,
nwords,
i,
bits;
_FSRead(svr, packbuffer, size);
lp = (long *) data;
lpack = (long *) packbuffer;
nwords = size >> 1;
bits = 48;
for (i = 0; i < nwords; i++) {
maskw = mask16 << bits;
*lp++ = (*lpack & maskw) >> bits;
bits -= 16;
if (bits < 0) {
lpack++;
bits = 48;
}
}
}
void
_FSRead16(svr, data, len)
FSServer *svr;
short *data;
long len;
{
char packbuffer[PACKBUFFERSIZE];
unsigned nwords = (PACKBUFFERSIZE >> 1);
for (; len > nwords; len -= nwords, data += nwords) {
_doFSRead16(svr, data, nwords, packbuffer);
}
_doFSRead16(svr, data, len, packbuffer);
}
void
_FSRead16Pad(svr, data, size)
FSServer *svr;
short *data;
long size;
{
int slop = (size & 3);
short slopbuf[3];
_FSRead16(svr, data, size);
if (slop > 0) {
_FSRead16(svr, slopbuf, 4 - slop);
}
}
#endif
void
_FSReadPad(svr, data, size)
register FSServer *svr;
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;
iov[1].iov_len = padlength[size & 3];
iov[1].iov_base = pad;
size += iov[1].iov_len;
ESET(0);
while ((bytes_read = _FSTransReadv(svr->trans_conn, iov, 2)) != size) {
if (bytes_read > 0) {
size -= bytes_read;
if (iov[0].iov_len < bytes_read) {
int pad_bytes_read = bytes_read - iov[0].iov_len;
iov[1].iov_len -= pad_bytes_read;
iov[1].iov_base =
(char *)iov[1].iov_base + pad_bytes_read;
iov[0].iov_len = 0;
} else {
iov[0].iov_len -= bytes_read;
iov[0].iov_base = (char *)iov[0].iov_base + bytes_read;
}
}
else if (ETEST()) {
_FSWaitForReadable(svr);
ESET(0);
}
#ifdef SUNSYSV
else if (ECHECK(0)) {
_FSWaitForReadable(svr);
}
#endif
else if (bytes_read == 0) {
ESET(EPIPE);
(*_FSIOErrorFunction) (svr);
} else {
if (!ECHECK(EINTR))
(*_FSIOErrorFunction) (svr);
}
}
}
void
_FSSend(svr, data, size)
register FSServer *svr;
char *data;
register long size;
{
struct iovec iov[3];
static char pad[3] = {0, 0, 0};
long skip = 0;
long svrbufsize = (svr->bufptr - svr->buffer);
long padsize = padlength[size & 3];
long total = svrbufsize + size + padsize;
long todo = total;
while (total) {
long before = skip;
long remain = todo;
int i = 0;
long len;
#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(svr->buffer, svrbufsize)
InsertIOV(data, size)
InsertIOV(pad, padsize)
ESET(0);
if ((len = _FSTransWritev(svr->trans_conn, iov, i)) >= 0) {
skip += len;
total -= len;
todo = total;
} else if (ETEST()) {
_FSWaitForWritable(svr);
#ifdef SUNSYSV
} else if (ECHECK(0)) {
_FSWaitForWritable(svr);
#endif
#ifdef EMSGSIZE
} else if (ECHECK(EMSGSIZE)) {
if (todo > 1)
todo >>= 1;
else
_FSWaitForWritable(svr);
#endif
} else {
(*_FSIOErrorFunction) (svr);
}
}
svr->bufptr = svr->buffer;
svr->last_req = (char *) &_dummy_request;
}
#ifdef undef
FSID
_FSAllocID(svr)
register FSServer *svr;
{
return (svr->resource_base + (svr->resource_id++ << svr->resource_shift));
}
#endif
unsigned long
_FSSetLastRequestRead(svr, rep)
register FSServer *svr;
register fsGenericReply *rep;
{
register unsigned long newseq,
lastseq;
newseq = (svr->last_request_read & ~((unsigned long) 0xffff)) |
rep->sequenceNumber;
lastseq = svr->last_request_read;
while (newseq < lastseq) {
newseq += 0x10000;
if (newseq > svr->request) {
(void) fprintf(stderr,
"FSlib: sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n",
newseq, svr->request,
(unsigned int) rep->type);
newseq -= 0x10000;
break;
}
}
svr->last_request_read = newseq;
return (newseq);
}
Status
_FSReply(svr, rep, extra, discard)
register FSServer *svr;
register fsReply *rep;
int extra;
Bool discard;
{
unsigned long cur_request = svr->request;
long rem_length;
_FSFlush(svr);
while (1) {
_FSRead(svr, (char *) rep, (long) SIZEOF(fsReply));
switch ((int) rep->generic.type) {
case FS_Reply:
if (rep->generic.sequenceNumber == (cur_request & 0xffff))
svr->last_request_read = cur_request;
else
(void) _FSSetLastRequestRead(svr, &rep->generic);
rem_length = rep->generic.length - (SIZEOF(fsReply) >> 2);
if (rem_length < 0) rem_length = 0;
if (extra == 0) {
if (discard && rem_length)
_EatData32(svr, rem_length);
return (1);
}
if (extra == rem_length) {
_FSRead(svr, (char *) NEXTPTR(rep, fsReply), ((long) extra) << 2);
return (1);
}
if (extra < rem_length) {
_FSRead(svr, (char *) NEXTPTR(rep, fsReply), ((long) extra) << 2);
if (discard)
_EatData32(svr, rem_length - extra);
return (1);
}
_FSRead(svr, (char *) NEXTPTR(rep, fsReply), rem_length << 2);
(*_FSIOErrorFunction) (svr);
return (0);
case FS_Error:
{
register _FSExtension *ext;
register Bool ret = False;
int ret_code;
fsError err;
unsigned long serial;
long err_data;
err = *(fsError *) rep;
_FSRead(svr, (char *) &err + SIZEOF(fsReply),
(long) (SIZEOF(fsError) - SIZEOF(fsReply)));
serial = _FSSetLastRequestRead(svr, (fsGenericReply *) rep);
if (serial == cur_request)
switch ((int) err.request) {
case FSBadResolution:
case FSBadLength:
case FSBadIDChoice:
case FSBadRange:
case FSBadFont:
case FSBadFormat:
_FSRead(svr, (char *) &err_data, 4);
break;
case FSBadAccessContext:
_FSRead(svr, (char *) &err_data, 4);
return 0;
case FSBadAlloc:
return (0);
default:
ext = svr->ext_procs;
while (ext) {
if (ext->error != NULL)
ret = (*ext->error)
(svr, &err, &ext->codes, &ret_code);
ext = ext->next;
}
if (ret)
return (ret_code);
break;
}
_FSError(svr, &err);
if (serial == cur_request)
return (0);
}
break;
default:
_FSEnq(svr, (fsEvent *) rep);
break;
}
}
}
void
_FSEatData(svr, n)
FSServer *svr;
register unsigned long n;
{
#define SCRATCHSIZE 2048
char buf[SCRATCHSIZE];
while (n > 0) {
register long bytes_read = (n > SCRATCHSIZE) ? SCRATCHSIZE : n;
_FSRead(svr, buf, bytes_read);
n -= bytes_read;
}
#undef SCRATCHSIZE
}
static void
_EatData32(svr, n)
FSServer *svr;
unsigned long n;
{
_FSEatData(svr, n << 2);
}
void
_FSEnq(svr, event)
register FSServer *svr;
register fsEvent *event;
{
register _FSQEvent *qelt;
if ((qelt = _FSqfree) != NULL) {
_FSqfree = qelt->next;
} else if ((qelt =
(_FSQEvent *) FSmalloc((unsigned) sizeof(_FSQEvent))) == NULL) {
ESET(ENOMEM);
(*_FSIOErrorFunction) (svr);
}
qelt->next = NULL;
if ((*svr->event_vec[event->type & 0177]) (svr, &qelt->event, event)) {
if (svr->tail)
svr->tail->next = qelt;
else
svr->head = qelt;
svr->tail = qelt;
svr->qlen++;
} else {
qelt->next = _FSqfree;
_FSqfree = qelt;
}
}
Bool
_FSUnknownWireEvent(svr, re, event)
register FSServer *svr;
register FSEvent *re;
register fsEvent *event;
{
#ifdef notdef
(void) fprintf(stderr,
"FSlib: unhandled wire event! event number = %d, display = %x\n.",
event->type, svr);
#endif
return (False);
}
Status
_FSUnknownNativeEvent(svr, re, event)
register FSServer *svr;
register FSEvent *re;
register fsEvent *event;
{
#ifdef notdef
(void) fprintf(stderr,
"FSlib: unhandled native event! event number = %d, display = %x\n.",
re->type, svr);
#endif
return (0);
}
Bool
_FSWireToEvent(svr, re, event)
register FSServer *svr;
register FSEvent *re;
register fsEvent *event;
{
re->type = event->type & 0x7f;
((FSAnyEvent *) re)->serial = _FSSetLastRequestRead(svr,
(fsGenericReply *) event);
((FSAnyEvent *) re)->send_event = ((event->type & 0x80) != 0);
((FSAnyEvent *) re)->server = svr;
switch (event->type & 0177) {
default:
return (_FSUnknownWireEvent(svr, re, event));
}
}
static char *
_SysErrorMsg(n)
int n;
{
char *s = strerror(n);
return (s ? s : "no such error");
}
int
_FSDefaultIOError(svr)
FSServer *svr;
{
(void) fprintf(stderr,
"FSIO: fatal IO error %d (%s) on font server \"%s\"\r\n",
#ifdef WIN32
WSAGetLastError(), strerror(WSAGetLastError()),
#else
errno, _SysErrorMsg(errno),
#endif
FSServerString(svr));
(void) fprintf(stderr,
" after %lu requests (%lu known processed) with %d events remaining.\r\n",
FSNextRequest(svr) - 1, FSLastKnownRequestProcessed(svr),
FSQLength(svr));
if (ECHECK(EPIPE)) {
(void) fprintf(stderr,
" The connection was probably broken by a server shutdown.\r\n");
}
exit(1);
}
int
_FSError(svr, rep)
FSServer *svr;
fsError *rep;
{
FSErrorEvent event;
event.server = svr;
event.type = FS_Error;
event.serial = _FSSetLastRequestRead(svr, (fsGenericReply *) rep);
event.error_code = rep->request;
event.request_code = rep->major_opcode;
event.minor_code = rep->minor_opcode;
if (_FSErrorFunction != NULL) {
return ((*_FSErrorFunction) (svr, &event));
}
exit(1);
}
int
_FSPrintDefaultError(svr, event, fp)
FSServer *svr;
FSErrorEvent *event;
FILE *fp;
{
char buffer[BUFSIZ];
char mesg[BUFSIZ];
char number[32];
char *mtype = "FSlibMessage";
register _FSExtension *ext = (_FSExtension *) NULL;
(void) FSGetErrorText(svr, event->error_code, buffer, BUFSIZ);
(void) FSGetErrorDatabaseText(svr, mtype, "FSError", "FS Error", mesg,
BUFSIZ);
(void) fprintf(fp, "%s: %s\n ", mesg, buffer);
(void) FSGetErrorDatabaseText(svr, 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);
(void) FSGetErrorDatabaseText(svr, "FSRequest", number, "", buffer,
BUFSIZ);
} else {
for (ext = svr->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);
(void) FSGetErrorDatabaseText(svr, mtype, "MinorCode",
"Request Minor code %d", mesg, BUFSIZ);
(void) fprintf(fp, mesg, event->minor_code);
if (ext) {
sprintf(mesg, "%s.%d", ext->name, event->minor_code);
(void) FSGetErrorDatabaseText(svr, "FSRequest", mesg, "", buffer,
BUFSIZ);
(void) fprintf(fp, " (%s)", buffer);
}
fputs("\n ", fp);
(void) FSGetErrorDatabaseText(svr, mtype, "ResourceID", "ResourceID 0x%x",
mesg, BUFSIZ);
(void) fprintf(fp, mesg, event->resourceid);
fputs("\n ", fp);
(void) FSGetErrorDatabaseText(svr, mtype, "ErrorSerial", "Error Serial #%d",
mesg, BUFSIZ);
(void) fprintf(fp, mesg, event->serial);
fputs("\n ", fp);
(void) FSGetErrorDatabaseText(svr, mtype, "CurrentSerial",
"Current Serial #%d", mesg, BUFSIZ);
(void) fprintf(fp, mesg, svr->request);
fputs("\n", fp);
return 1;
}
int
_FSDefaultError(svr, event)
FSServer *svr;
FSErrorEvent *event;
{
if (_FSPrintDefaultError(svr, event, stderr) == 0)
return 0;
exit(1);
}
FSIOErrorHandler _FSIOErrorFunction = _FSDefaultIOError;
FSErrorHandler _FSErrorFunction = _FSDefaultError;
char *
_FSAllocScratch(svr, nbytes)
register FSServer *svr;
unsigned long nbytes;
{
if (nbytes > svr->scratch_length) {
if (svr->scratch_buffer != NULL)
FSfree(svr->scratch_buffer);
return (svr->scratch_length = nbytes,
svr->scratch_buffer = FSmalloc((unsigned) nbytes));
}
return (svr->scratch_buffer);
}
int
FSFree(data)
char *data;
{
FSfree(data);
return 1;
}
unsigned char *
FSMalloc(size)
unsigned size;
{
return (unsigned char *) FSmalloc(size);
}
#ifdef DataRoutineIsProcedure
void
Data(svr, data, len)
FSServer *svr;
char *data;
long len;
{
if (svr->bufptr + (len) <= svr->bufmax) {
bcopy(data, svr->bufptr, (int) len);
svr->bufptr += ((len) + 3) & ~3;
} else {
_FSSend(svr, data, len);
}
}
#endif
#ifdef WORD64
static void
doData16(svr, data, len, packbuffer)
register FSServer *svr;
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 = 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(svr, packbuffer, len);
}
void
Data16(svr, data, len)
FSServer *svr;
short *data;
unsigned len;
{
char packbuffer[PACKBUFFERSIZE];
unsigned nwords = (PACKBUFFERSIZE >> 1);
for (; len > nwords; len -= nwords, data += nwords) {
doData16(svr, data, nwords, packbuffer);
}
doData16(svr, data, len, packbuffer);
}
static
doData32(svr, data, len, packbuffer)
register FSServer *svr;
long *data;
unsigned len;
char *packbuffer;
{
long *lp,
*lpack;
long i,
bits,
nwords;
long mask32 = 0x00000000ffffffff;
lpack = (long *) packbuffer;
lp = data;
*lpack = 0;
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(svr, packbuffer, len);
}
void
Data32(svr, data, len)
FSServer *svr;
short *data;
unsigned len;
{
char packbuffer[PACKBUFFERSIZE];
unsigned nwords = (PACKBUFFERSIZE >> 2);
for (; len > nwords; len -= nwords, data += nwords) {
doData32(svr, data, nwords, packbuffer);
}
doData32(svr, data, len, packbuffer);
}
#endif
void
_FSFreeQ()
{
register _FSQEvent *qelt = _FSqfree;
while (qelt) {
register _FSQEvent *qnext = qelt->next;
FSfree(qelt);
qelt = qnext;
}
_FSqfree = NULL;
return;
}
#ifdef _POSIX_SOURCE
#ifndef __QNX__
#define NEED_UTSNAME
#endif
#endif
#ifdef hpux
#define NEED_UTSNAME
#endif
#ifdef USG
#define NEED_UTSNAME
#endif
#ifdef SVR4
#ifndef _SEQUENT_
#define NEED_UTSNAME
#endif
#endif
#ifdef NEED_UTSNAME
#include <sys/utsname.h>
#endif
int
_FSGetHostname(buf, maxlen)
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
return len;
}
#ifndef _FSANYSET
_FSANYSET(src)
long *src;
{
int i;
for (i=0; i<MSKCNT; i++)
if (src[ i ])
return (1);
return (0);
}
#endif