[comp.sources.x] v09i017: Xmon - X protocol monitor, Part03/05

gregm@otc.otca.oz.au (Greg McFarlane) (09/05/90)

Submitted-by: Greg McFarlane <gregm@otc.otca.oz.au>
Posting-number: Volume 9, Issue 17
Archive-name: xmon/part03

Submitted-by: gregm@otc.otca.oz.au
Archive-name: xmon/part03

---- Cut Here and unpack ----
#!/bin/sh
# This is part 03 of xmon
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= server.c ==============
if test X"$1" != X"-c" -a -f 'server.c'; then
	echo "File already exists: skipping 'server.c'"
else
echo "x - extracting server.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > server.c &&
X/*
X * Project: XMON - An X protocol monitor
X *
X * File: server.c
X *
X * Description: Code to decode and print X11 protocol
X
X * These are the possible values for ByteProcessing:
X *   For clients:
X *	    StartSetUpMessage
X *	    FinishSetUpMessage
X *	    StartRequest
X *	    FinishRequest
X *   For servers:
X *	    StartSetUpReply
X *	    FinishSetUpReply
X *	    ServerPacket
X *	    FinishReply
X *
X */
X
X#include <sys/time.h>          /* for struct timeval * */
X#include <errno.h>             /* for EINTR, EADDRINUSE, ... */
X
X#include "common.h"
X
X#include "x11.h"
X#include "xmond.h"
X
X/* function prototypes: */
X/* server.c: */
Xstatic void ProcessBuffer P((int fd , unsigned char *buf , long n , int
WriteFD ));
Xstatic void WriteBuffer P((Client *client , long n , char *buf , int
WriteFD ));
Xstatic long StartSetUpMessage P((Pointer private_data , unsigned char
*buf , long n ));
Xstatic long FinishSetUpMessage P((Pointer private_data , unsigned char
*buf , long n ));
Xstatic long StartRequest P((Pointer private_data , unsigned char *buf ,
long n ));
Xstatic long FinishRequest P((Pointer private_data , unsigned char *buf
, long n ));
Xstatic long StartSetUpReply P((Pointer private_data , unsigned char
*buf , long n ));
Xstatic long FinishSetUpReply P((Pointer private_data , unsigned char
*buf , long n ));
Xstatic long ErrorPacket P((Server *server , unsigned char *buf , long n ));
Xstatic long EventPacket P((Server *server , unsigned char *buf , long n ));
Xstatic long ReplyPacket P((Server *server , unsigned char *buf , long n ));
Xstatic long ServerPacket P((Pointer private_data , unsigned char *buf ,
long n ));
Xstatic long FinishReply P((Pointer private_data , unsigned char *buf ,
long n ));
X
X/* end function prototypes */
X
XGlobal Bool					ignore_bytes;
X
Xextern int					CurrentVerbose;
Xextern int					ErrorVerbose;
Xextern Bool					littleEndian;
X
Xstatic long ZeroTime1 = -1;
Xstatic long ZeroTime2 = -1;
Xstatic struct timeval   tp;
X
X/*
X * print the time since we started in hundredths (1/100) of seconds
X */
X
XGlobal void
XPrintTime()
X{
X	static long lastsec = 0;
X	long    sec /* seconds */ ;
X	long    hsec /* hundredths of a second */ ;
X
X	gettimeofday(&tp, (struct timezone *)NULL);
X	if (ZeroTime1 == -1 || (tp.tv_sec - lastsec) >= 1000)
X		{
X			ZeroTime1 = tp.tv_sec;
X			ZeroTime2 = tp.tv_usec / 10000;
X		}
X
X	lastsec = tp.tv_sec;
X	sec = tp.tv_sec - ZeroTime1;
X	hsec = tp.tv_usec / 10000 - ZeroTime2;
X	if (hsec < 0)
X		{
X			hsec += 100;
X			sec -= 1;
X		}
X	fprintf(stdout, "%2d.%02ld: ", sec, hsec);
X}
X
X/*
X * pad:
X * 
X * we will need to be able to interpret the values stored in the requests
X * as various built-in types.  The following routines support the types
X * built into X11
X */
XGlobal int
Xpad (n)
X		long    n;
X{
X	/* round up to next multiple of 4 */
X	return((n + 3) & ~0x3);
X}
X
XGlobal unsigned long
XILong (buf)
X		unsigned char   buf[];
X{
X	if (littleEndian)
X		return((((((buf[3] << 8) | buf[2]) << 8) | buf[1]) << 8) | buf[0]);
X	return((((((buf[0] << 8) | buf[1]) << 8) | buf[2]) << 8) | buf[3]);
X}
X
XGlobal unsigned short
XIShort (buf)
Xunsigned char   buf[];
X{
X	if (littleEndian)
X		return (buf[1] << 8) | buf[0];
X	return((buf[0] << 8) | buf[1]);
X}
X
XGlobal unsigned short
XIByte (buf)
Xunsigned char   buf[];
X{
X	return(buf[0]);
X}
X
XGlobal Bool
XIBool(buf)
X		unsigned char   buf[];
X{
X	if (buf[0] != 0)
X		return(True);
X	else
X		return(False);
X}
X
X/*
X * Byte Processing Routines.  Each routine MUST set num_Needed
X * and ByteProcessing.  It probably needs to do some computation first.
X */
X
XGlobal void
XStartClientConnection(client)
X	Client *client;
X{
X	/* when a new connection is started, we have no saved bytes */
X	client->fdd->inBuffer.data = NULL;
X	client->fdd->inBuffer.BlockSize = 0;
X	client->fdd->inBuffer.num_Saved = 0;
X	client->fdd->outBuffer.data = NULL;
X	client->fdd->outBuffer.BlockSize = 0;
X	client->fdd->outBuffer.num_Saved = 0;
X
X	/* each new connection gets a request sequence number */
X	client->SequenceNumber = 0;
X
X	/* we need 12 bytes to start a SetUp message */
X	client->fdd->ByteProcessing = StartSetUpMessage;
X	client->fdd->inBuffer.num_Needed = 12;
X}
X
XGlobal void
XStartServerConnection(server)
X	Server *server;
X{
X	/* when a new connection is started, we have no saved bytes */
X	server->fdd->inBuffer.data = NULL;
X	server->fdd->inBuffer.BlockSize = 0;
X	server->fdd->inBuffer.num_Saved = 0;
X	server->fdd->outBuffer.data = NULL;
X	server->fdd->outBuffer.BlockSize = 0;
X	server->fdd->outBuffer.num_Saved = 0;
X
X	/* when a new connection is started, we have no reply Queue */
X	initList(&server->reply_list);
X
X	/* we need 8 bytes to start a SetUp reply */
X	server->fdd->ByteProcessing = StartSetUpReply;
X	server->fdd->inBuffer.num_Needed = 8;
X}
X
Xstatic void
XWriteBuffer(client, n, buf, WriteFD)
X	Client					*client;
X	long					n;
X	char					*buf;
X	int						WriteFD;
X{
X	int						BytesToWrite = n;
X	int						num_written;
X
X	while (BytesToWrite > 0)
X	{
X		num_written = write (WriteFD, buf, BytesToWrite);
X		if (num_written > 0)
X		{
X			BytesToWrite -= num_written;
X			buf += num_written;
X		}
X		else
X		{
X			if (errno == EWOULDBLOCK)
X				printf("WriteBuffer: write would block (TODO)\n");
X			if (errno == EINTR)
X				printf("WriteBuffer: write interrupted (TODO)\n");
X			perror("Error on write to Client/Server");
X			CloseConnection(client);
X			BytesToWrite = 0;
X		}
X	}
X}
X
X/*
X * StartSetUpMessage:
X *
X * we need the first 12 bytes to be able to determine if, and how many,
X * additional bytes we need for name and data authorization.  However, we
X * can't process the first 12 bytes until we get all of them, so
X * return zero bytes used, and increase the number of bytes needed
X */
Xstatic long
XStartSetUpMessage (private_data, buf, n)
X	Pointer					private_data;
X	unsigned char			*buf;
X	long					n;
X{
X	Client					*client = (Client *) private_data;
X	short					namelength;
X	short					datalength;
X
X	namelength = IShort(&buf[6]);
X	datalength = IShort(&buf[8]);
X	client->fdd->ByteProcessing = FinishSetUpMessage;
X	client->fdd->inBuffer.num_Needed =
X		n + pad((long)namelength) + pad((long)datalength);
X	return(0);
X}
X
Xstatic long
XFinishSetUpMessage (private_data, buf, n)
X	Pointer					private_data;
X	unsigned char			*buf;
X	long					n;
X{
X	Client					*client = (Client *) private_data;
X
X	littleEndian = client->fdd->littleEndian = (buf[0] == 'l');
X
X	CurrentVerbose = ErrorVerbose;
X	PrintSetUpMessage(buf);
X
X	/* after a set-up message, we expect a string of requests */
X	client->fdd->ByteProcessing = StartRequest;
X	client->fdd->inBuffer.num_Needed = 4;
X	return(n);
X}
X
X
Xstatic long
XStartRequest (private_data, buf, n)
X	Pointer					private_data;
X	unsigned char			*buf;
X	long					n;
X{
X	short					requestlength = IShort(&buf[2]);
X	Client					*client = (Client *) private_data;
X
X	client->fdd->ByteProcessing = FinishRequest;
X	client->fdd->inBuffer.num_Needed = 4 * requestlength;
X	return(0);
X}
X
X
Xstatic long
XFinishRequest (private_data, buf, n)
X	Pointer					private_data;
X	unsigned char			*buf;
X	long					n;
X{
X	Client					*client = (Client *) private_data;
X
X	DecodeRequest(client, buf, n);
X	client->fdd->ByteProcessing = StartRequest;
X	client->fdd->inBuffer.num_Needed = 4;
X	return(n);
X}
X
Xstatic long
XStartSetUpReply (private_data, buf, n)
X	Pointer					private_data;
X	unsigned char			*buf;
X	long					n;
X{
X	short					replylength = IShort(&buf[6]);
X	Server					*server = (Server *) private_data;
X
X	server->fdd->ByteProcessing = FinishSetUpReply;
X	server->fdd->inBuffer.num_Needed = n + 4 * replylength;
X	return(0);
X}
X
Xstatic long
XFinishSetUpReply (private_data, buf, n)
X	Pointer					private_data;
X	unsigned char			*buf;
X	long					n;
X{
X	Server					*server = (Server *) private_data;
X
X	CurrentVerbose = ErrorVerbose;
X	PrintSetUpReply(buf);
X	server->fdd->ByteProcessing = ServerPacket;
X	server->fdd->inBuffer.num_Needed = 32;
X	return(n);
X}
X
Xstatic long
XErrorPacket (server, buf, n)
X	Server					*server;
X	unsigned char			*buf;
X	long					n;
X{
X	DecodeError(server, buf, n);
X	server->fdd->ByteProcessing = ServerPacket;
X	server->fdd->inBuffer.num_Needed = 32;
X	return(n);
X}
X
X
Xstatic long
XEventPacket (server, buf, n)
X	Server					*server;
X	unsigned char			*buf;
X	long					n;
X{
X	DecodeEvent(server, buf, n);
X	server->fdd->ByteProcessing = ServerPacket;
X	server->fdd->inBuffer.num_Needed = 32;
X	return(n);
X}
X
X/*
X	Replies may need more bytes, so we compute how many more
X	bytes are needed and ask for them, not using any of the bytes
X	we were given (return(0) to say that no bytes were used).
X	If the replylength is zero (we don't need any more bytes), the
X	number of bytes needed will be the same as what we have, and
X	so the top-level loop will call the next routine immediately
X	with the same buffer of bytes that we were given.
X*/
Xstatic long
XReplyPacket (server, buf, n)
X	Server					*server;
X	unsigned char			*buf;
X	long					n;
X{
X	short					replylength = ILong(&buf[4]);
X
X	server->fdd->ByteProcessing = FinishReply;
X	server->fdd->inBuffer.num_Needed = n + 4 * replylength;
X	return(0);
X}
X
Xstatic long
XServerPacket (private_data, buf, n)
X	Pointer					private_data;
X	unsigned char			*buf;
X	long					n;
X{
X	short					PacketType = IByte(&buf[0]);
X	Server					*server = (Server *) private_data;
X
X	if (PacketType == 0)
X		return(ErrorPacket(server, buf, n));
X	else if (PacketType == 1)
X		return(ReplyPacket(server, buf, n));
X	else
X		return(EventPacket(server, buf, n));
X}
X
Xstatic long
XFinishReply (private_data, buf, n)
X	Pointer					private_data;
X	unsigned char			*buf;
X	long					n;
X{
X	Server					*server = (Server *) private_data;
X
X	DecodeReply(server, buf, n);
X	server->fdd->ByteProcessing = ServerPacket;
X	server->fdd->inBuffer.num_Needed = 32;
X	return(n);
X}
SHAR_EOF
$TOUCH -am 0903162990 server.c &&
chmod 0664 server.c ||
echo "restore of server.c failed"
set `wc -c server.c`;Wc_c=$1
if test "$Wc_c" != "9529"; then
	echo original size 9529, current size $Wc_c
fi
fi
# ============= fd.c ==============
if test X"$1" != X"-c" -a -f 'fd.c'; then
	echo "File already exists: skipping 'fd.c'"
else
echo "x - extracting fd.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > fd.c &&
X/*
X * Project: XMON - An X protocol monitor
X * 
X * File: fd.c
X * 
X * Description: Support routines for file descriptors
X * 
X * All of this code is to support the handling of file descriptors.
X * The idea is to keep a table of the FDs that are in use and why.  For
X * each FD that is open for input, we keep the name of a procedure to call
X * if input arrives for that FD.  When an FD is created (by an open, pipe,
X * socket, ...) declare that by calling UsingFD.  When it is no longer in
X * use (close ...), call NotUsingFD.
X */
X
X#include <errno.h>             /* for EINTR, EADDRINUSE, ... */
X
X#include "common.h"
X
X#include "xmond.h"
X#include "select_args.h"
X
X/* function prototypes: */
X/* fd.c: */
X
X/* end function prototypes */
X
Xextern FDDescriptor				*FDD;
Xextern long						ReadDescriptors[];
Xextern long						WriteDescriptors[];
Xextern short					HighestFD;
X
XGlobal void
XInitializeFD()
X{
X	register short  i;
X	short   MaxFD /* maximum number of FD's possible */ ;
X
X	enterprocedure("InitializeFD");
X	/* get the number of file descriptors the system will let us use */
X	MaxFD = getdtablesize();
X
X	/* allocate space for a File Descriptor Table */
X	FDD = (FDDescriptor *)malloc((long)(MaxFD * sizeof(FDDescriptor)));
X
X	for (i = 0; i < MaxFD; i++)
X		FDD[i].InputHandler = (VoidCallback)NULL;
X
X	CLEARBITS(ReadDescriptors);
X	CLEARBITS(WriteDescriptors);
X	HighestFD = 0;
X}
X
XGlobal FDDescriptor*
XUsingFD(fd, Handler, private_data)
X	int						fd;
X	VoidCallback			Handler;
X	Pointer					private_data;
X{
X	FDD[fd].InputHandler = Handler;
X	FDD[fd].private_data = private_data;
X	if (Handler == NULL)
X		BITCLEAR(ReadDescriptors, fd);
X	else
X		BITSET(ReadDescriptors, fd);
X
X	if (fd > HighestFD)
X		HighestFD = fd;
X	return &FDD[fd];
X}
X
XGlobal void
XNotUsingFD(fd)
X		int fd;
X{
X	FDD[fd].InputHandler = (VoidCallback)NULL;
X	BITCLEAR(ReadDescriptors, fd);
X
X	while (FDD[HighestFD].InputHandler == (VoidCallback)NULL && HighestFD > 0)
X		HighestFD -= 1;
X}
X
XGlobal void
XEOFonFD(fd)
X		int fd;
X{
X	close(fd);
X	NotUsingFD(fd);
X}
SHAR_EOF
$TOUCH -am 0903162990 fd.c &&
chmod 0664 fd.c ||
echo "restore of fd.c failed"
set `wc -c fd.c`;Wc_c=$1
if test "$Wc_c" != "1997"; then
	echo original size 1997, current size $Wc_c
fi
fi
# ============= main.c ==============
if test X"$1" != X"-c" -a -f 'main.c'; then
	echo "File already exists: skipping 'main.c'"
else
echo "x - extracting main.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > main.c &&
X/*
X * Project: XMON - An X protocol monitor
X *
X * File: main.c
X *
X * Description: Contains main() for xmond
X *
X */
X
X#include <sys/types.h>         /* needed by sys/socket.h and netinet/in.h */
X#include <sys/uio.h>           /* for struct iovec, used by socket.h */
X#include <sys/socket.h>        /* for AF_INET, SOCK_STREAM, ... */
X#include <sys/ioctl.h>         /* for FIONCLEX, FIONBIO, ... */
X#include <netinet/in.h>        /* struct sockaddr_in */
X#include <netdb.h>             /* struct servent * and struct hostent * */
X#include <errno.h>             /* for EINTR, EADDRINUSE, ... */
X#include <signal.h>
X
X#include "common.h"
X
X#include "linkl.h"
X#include "xmond.h"
X#include "select_args.h"
X
X#define BACKLOG					5
X#define XBasePort				6000
X#define NUM_REQUESTS			/* 128 */ 256
X#define NUM_EVENTS				/* 40 */ 256
X
X
X/* function prototypes: */
X/* main.c: */
Xstatic void ScanArgs P((int argc , char **argv ));
Xstatic void SetUpConnectionSocket P((int iport ));
Xstatic void SetSignalHandling P((void ));
Xstatic void MainLoop P((void ));
Xstatic Bool SendBuffer P((int fd , Buffer *buffer ));
Xstatic short GetServerport P((void ));
Xstatic short GetScopePort P((void ));
Xstatic void Usage P((void ));
Xstatic void ReadStdin P((Pointer private_data ));
Xstatic void NewConnection P((Pointer private_data ));
Xstatic void DataFromClient P((Pointer private_data ));
Xstatic void DataFromServer P((Pointer private_data ));
Xstatic Bool ReadAndProcessData P((Pointer private_data , FDDescriptor
*read_fdd , FDDescriptor *write_fdd ));
Xstatic void SaveBytes P((Buffer *buffer , char *buf , long n ));
Xstatic void RemoveSavedBytes P((Buffer *buffer , int n ));
Xstatic int ConnectToClient P((int ConnectionSocket ));
Xstatic int ConnectToServer P((char *hostName ));
Xstatic char *OfficialName P((char *name ));
Xstatic void SignalURG P((void ));
Xstatic void SignalPIPE P((void ));
Xstatic void SignalINT P((void ));
Xstatic void SignalQUIT P((void ));
Xstatic void SignalTERM P((void ));
Xstatic void SignalTSTP P((void ));
Xstatic void SignalCONT P((void ));
X
X/* end function prototypes */
X
XGlobal Bool    ignore_bytes;
XGlobal int     RequestVerbose = 0;		/* verbose level for requests */
XGlobal int     EventVerbose = 0;		/* verbose level for events */
XGlobal int     ReplyVerbose = 0;		/* verbose level for replies */
XGlobal int     ErrorVerbose = 1;		/* verbose level for error */
XGlobal Bool	   VerboseRequest[NUM_REQUESTS];/* requests that are very
verbose */
XGlobal Bool	   VerboseEvent[NUM_EVENTS];	/* events that are very verbose */
XGlobal Bool	   BlockRequest[NUM_REQUESTS];	/* do not transmit these
requests */
XGlobal Bool	   BlockEvent[NUM_EVENTS];		/* do not transmit these events */
XGlobal Bool    MonitoringRequests = True;	/* monitor selected requests? */
XGlobal Bool    MonitoringEvents = True;		/* monitor selected events? */
XGlobal Bool    BlockingRequests = True;		/* block selected requests? */
XGlobal Bool    BlockingEvents = True;		/* block selected events? */
XGlobal int     SelectedRequestVerbose = 3;	/* selected requests verboseness */
XGlobal int     SelectedEventVerbose = 3;	/* selected errors verboseness */
XGlobal char    ServerHostName[255];
XGlobal char    *LocalHostName;
XGlobal int     debuglevel = 0;
XGlobal LinkList	client_list;		/* list of Client */
XGlobal FDDescriptor *FDD;
XGlobal long		ReadDescriptors[mskcnt];
XGlobal long		WriteDescriptors[mskcnt];
XGlobal short	HighestFD;
XGlobal Bool		littleEndian;
X
Xstatic long			ClientNumber = 0;
Xstatic int				ServerPort = 0;
Xstatic int				ListenForClientsPort = 1;
X
XGlobal void
Xmain(argc, argv)
X		int     argc;
X		char  **argv;
X{
X	int i;
X
X	ScanArgs(argc, argv);
X	InitializeFD();
X	InitializeX11();
X	InitRequestCount();
X	InitEventCount();
X	InitErrorCount();
X	(void)UsingFD(fileno(stdin), ReadStdin, (Pointer)fileno(stdin));
X	SetUpConnectionSocket(GetScopePort());
X	SetSignalHandling();
X	for (i = 0; i < NUM_REQUESTS; i++)
X		BlockRequest[i] = VerboseRequest[i] = False;
X	for (i = 0; i < NUM_EVENTS; i++)
X		BlockEvent[i] = VerboseEvent[i] = False;
X	initList(&client_list);
X	MainLoop();
X}
X
XGlobal void
XCloseConnection(client)
X	Client					*client;
X{
X	Server					*server;
X
X	if (client->fdd->outBuffer.BlockSize > 0)
X		Tfree(client->fdd->outBuffer.data);
X	if (client->fdd->inBuffer.BlockSize > 0)
X		Tfree(client->fdd->inBuffer.data);
X	close(client->fdd->fd);
X	NotUsingFD(client->fdd->fd);
X
X	server = (Server *)(TopOfList(&client->server_list));
X	if (server->fdd->outBuffer.BlockSize > 0)
X		Tfree(server->fdd->outBuffer.data);
X	if (server->fdd->inBuffer.BlockSize > 0)
X		Tfree(server->fdd->inBuffer.data);
X	close(server->fdd->fd);
X	NotUsingFD(server->fdd->fd);
X}
X
Xstatic void
XScanArgs(argc, argv)
X		int     argc;
X		char  **argv;
X{
X	int i;
X
X	/* Scan argument list */
X	for (i = 1; i < argc; i++)
X		{
X			if (Streq(argv[i], "-server"))
X			{
X				/*	Generally of the form server_name:display_number.
X				 *	These all mean port 0 on server blah:
X				 *		"blah",
X				 *		"blah:",
X				 *		"blah:0"
X				 *	This means port 0 on local host: ":0".
X				 */
X				if (++i < argc || argv[i] == NULL || argv[i][0] == '\0')
X				{
X					char *index = strchr(argv[i], ':');
X					if (index == NULL)
X						ServerPort = 0;
X					else
X					{
X						ServerPort = atoi(index + 1);
X						*index = '\0';
X					}
X					if (ServerPort < 0)
X						ServerPort = 0;
X					if (index != argv[i])
X						strcpy(ServerHostName, OfficialName(argv[i]));
X				}
X				else
X						Usage();
X				debug(1,(stderr, "ServerHostName=%s\n", ServerHostName));
X			}
X			else if (Streq(argv[i], "-port"))
X			{
X				if (++i < argc)
X						ListenForClientsPort = atoi(argv[i]);
X				else
X						Usage();
X				if (ListenForClientsPort <= 0)
X					ListenForClientsPort = 0;
X				debug(1,(stderr, "ListenForClientsPort=%d\n",ListenForClientsPort));
X			}
X			else if (Streq(argv[i], "-debug"))
X			{
X				/*
X					debug levels:
X						2 - trace each procedure entry
X						4 - I/O, connections
X						8 - Scope internals
X						16 - Message protocol
X						32 - 64 - malloc
X						128 - 256 - really low level
X				*/
X				if (++i < argc)
X						debuglevel = atoi(argv[i]);
X				else
X						Usage();
X				if (debuglevel == 0)
X					debuglevel = 255;
X				debuglevel |= 1;
X				debug(1,(stderr, "debuglevel = %d\n", debuglevel));
X			}
X			else if (Streq(argv[i], "-verbose"))
X			{
X				if (++i < argc)
X					RequestVerbose = EventVerbose =
X						ReplyVerbose = ErrorVerbose = atoi(argv[i]);
X				else
X					Usage();
X			}
X			else
X				Usage();
X		}
X
X	LocalHostName = (char *)malloc(255);
X	(void) gethostname(LocalHostName, 255);
X	if (ServerHostName[0] == '\0')
X		(void) gethostname(ServerHostName, sizeof (ServerHostName));
X	if (Streq(ServerHostName,LocalHostName) && ListenForClientsPort ==
ServerPort)
X		{
X			fprintf
X			(
X				stderr, "Can't have xmond on same port as server (%d)\n",
X				ListenForClientsPort
X			);
X			Usage();
X		}
X}
X
X/*
X * SetUpConnectionSocket:
X *
X * Create a socket for a service to listen for clients
X */
Xstatic void
XSetUpConnectionSocket(iport)
Xint                     iport;
X{
X	int                   ON = 1;         /* used in ioctl */
X	int                    ConnectionSocket;
X	struct sockaddr_in    sin;
X
X	enterprocedure("SetUpConnectionSocket");
X
X	/* create the connection socket and set its parameters of use */
X	ConnectionSocket = socket(AF_INET, SOCK_STREAM, 0);
X	if (ConnectionSocket < 0)
X		{
X			perror("socket");
X			exit(-1);
X		}
X	(void)setsockopt(ConnectionSocket, SOL_SOCKET, SO_REUSEADDR, (char
*)NULL, 0);
X	(void)setsockopt(ConnectionSocket, SOL_SOCKET, SO_USELOOPBACK,
(char*)NULL,0);
X#ifdef SO_DONTLINGER
X	(void)setsockopt(ConnectionSocket, SOL_SOCKET, SO_DONTLINGER,
(char*)NULL, 0);
X#endif
X
X	/* define the name and port to be used with the connection socket */
X	bzero((char *)&sin, sizeof(sin));
X	sin.sin_family = AF_INET;
X
X	/* the address of the socket is composed of two parts: the host machine and
X		the port number.  We need the host machine address for the current host
X	*/
X	{
X		/* define the host part of the address */
X		struct hostent *hp;
X
X		hp = gethostbyname(LocalHostName);
X		if (hp == NULL)
X			panic("No address for our host"); /* and exit */
X		bcopy((char *)hp->h_addr, (char*)&sin.sin_addr, hp->h_length);
X	}
X		/* new code -- INADDR_ANY should be better than using the name of the
X			host machine.  The host machine may have several different network
X			addresses.  INADDR_ANY should work with all of them at once. */
X	sin.sin_addr.s_addr = INADDR_ANY;
X
X	sin.sin_port = htons (iport);
X
X	/* bind the name and port number to the connection socket */
X	if (bind(ConnectionSocket, (struct sockaddr *)&sin, sizeof(sin)) < 0)
X		{
X			perror("bind");
X			exit(-1);
X		}
X
X	debug(4,(stderr, "Socket is FD %d for %s,%d\n",
X					ConnectionSocket, LocalHostName, iport));
X
X	/* now activate the named connection socket to get messages */
X	if (listen(ConnectionSocket, BACKLOG) < 0)
X		{
X			perror("listen");
X			exit(-1);
X		};
X
X	/* a few more parameter settings */
X	ioctl(ConnectionSocket, FIOCLEX, 0);
X	ioctl(ConnectionSocket, FIONBIO, &ON);
X
X	debug(4,(stderr, "Listening on FD %d\n", ConnectionSocket));
X	(void)UsingFD(ConnectionSocket, NewConnection, (Pointer)ConnectionSocket);
X}
X
X/*
X * Signal Handling support
X */
Xstatic void
XSetSignalHandling()
X{
X	enterprocedure("SetSignalHandling");
X	signal(SIGURG, SignalURG);
X	signal(SIGPIPE, SignalPIPE);
X	signal(SIGINT, SignalINT);
X	signal(SIGQUIT, SignalQUIT);
X	signal(SIGTERM, SignalTERM);
X	signal(SIGTSTP, SignalTSTP);
X	signal(SIGCONT, SignalCONT);
X}
X
X/*
X * MainLoop:
X * 
X * Wait for input from any source and Process.
X */
Xstatic void
XMainLoop()
X{
X	long					rfds[mskcnt];
X	long					wfds[mskcnt];
X	long					xfds[mskcnt];
X	short					nfds;
X	short					fd;
X	Client					*client;
X	Server					*server;
X
X	while (True)
X	{
X		COPYBITS(ReadDescriptors, rfds);
X		COPYBITS(WriteDescriptors, wfds);
X		ORBITS(xfds, ReadDescriptors, WriteDescriptors);
X		nfds = select
X		(
X			HighestFD + 1, (fd_set *)rfds, (fd_set *)wfds, (fd_set *)xfds, NULL
X		);
X		if (ANYSET(xfds))
X			panic("MainLoop: error in select");
X		if (nfds <= 0)
X		{
X			if (errno != EINTR)
X				if (errno == EBADF)
X					EOFonFD(HighestFD);
X				else
X					panic("Select returns error");
X		}
X		else
X		{
X			for (fd = 0; ANYSET(rfds) && fd <= HighestFD; fd++)
X			{
X				if (GETBIT(rfds, fd))
X				{
X					BITCLEAR(rfds, fd);
X					(FDD[fd].InputHandler)(FDD[fd].private_data);
X				}
X			}
X			for (fd = 0; ANYSET(wfds) && fd <= HighestFD; fd++)
X			{
X				if (GETBIT(wfds, fd))
X				{
X					BITCLEAR(wfds, fd);
X					if (!SendBuffer(fd, &FDD[fd].outBuffer))
X						panic("help: which connection do we shut down (TODO?");
X				}
X			}
X		}
X		ForAllInList(&client_list)
X		{
X			client = (Client *)CurrentContentsOfList(&client_list);
X			if (!SendBuffer(client->fdd->fd, &client->fdd->outBuffer))
X				CloseConnection(client);
X			server = (Server *)(TopOfList(&client->server_list));
X			if (!SendBuffer(server->fdd->fd, &server->fdd->outBuffer))
X				CloseConnection(client);
X		}
X	}
X}
X
Xstatic Bool
XSendBuffer(fd, buffer)
X	int						fd;
X	Buffer					*buffer;
X{
X	char					*buf = buffer->data;
X	int						BytesToWrite = buffer->num_Saved;
X	int						num_written;
X	int						total_num_written = 0;
X	Bool					ok = True;
X
X	BITCLEAR(WriteDescriptors, fd);
X	if (BytesToWrite > 0)
X	{
X		do
X		{
X			num_written = write (fd, buf, BytesToWrite);
X			if (num_written > 0)
X			{
X				BytesToWrite -= num_written;
X				buf += num_written;
X				total_num_written += num_written;
X			}
X		}
X		while (BytesToWrite > 0 && num_written > 0);
X
X		if (BytesToWrite > 0)
X		{
X			if (errno == EWOULDBLOCK || errno == EINTR)
X			{
X				debug(4,(stderr, "write is blocked: buffering output\n"));
X				RemoveSavedBytes(buffer, total_num_written);
X				BITSET(WriteDescriptors, fd);
X			}
X			else
X			{
X				perror("Error on write to Client/Server");
X				ok = False;
X			}
X		}
X		else
X			buffer->num_Saved = 0;
X	}
X	return ok;
X}
X
Xstatic short
XGetServerport ()
X{
X	short     port;
X
X	enterprocedure("GetServerport");
X
X	port = XBasePort + ServerPort;
X	debug(4,(stderr, "Server service is on port %d\n", port));
X	return(port);
X}
X
Xstatic short
XGetScopePort ()
X{
X	short     port;
X
X	enterprocedure("GetScopePort");
X
X	port = XBasePort + ListenForClientsPort;
X	debug(4,(stderr, "xmond service is on port %d\n", port));
X	return(port);
X}
X
Xstatic void
XUsage()
X{
X	fprintf(stderr, "Usage: xmond\n");
X	fprintf(stderr, "              [-server <server_name:port>]\n");
X	fprintf(stderr, "              [-port <listen_port>]\n");
X	fprintf(stderr, "              [-debug <debug_level>]\n");
X	fprintf(stderr, "              [-verbose <all_monitor_level>]\n");
X	exit(1);
X}
X
X#define SELECTED_REQUEST_VERBOSE_STR		"selected_request_verbose"
X#define SELECTED_EVENT_VERBOSE_STR			"selected_event_verbose"
X#define REQUEST_VERBOSE_STR					"request_verbose"
X#define EVENT_VERBOSE_STR					"event_verbose"
X#define REPLY_VERBOSE_STR					"reply_verbose"
X#define ERROR_VERBOSE_STR					"error_verbose"
X#define MONITOR_REQUEST_ON_STR				"monitor_request_on"
X#define MONITOR_REQUEST_OFF_STR				"monitor_request_off"
X#define MONITOR_EVENT_ON_STR				"monitor_event_on"
X#define MONITOR_EVENT_OFF_STR				"monitor_event_off"
X#define BLOCK_REQUEST_ON_STR				"block_request_on"
X#define BLOCK_REQUEST_OFF_STR				"block_request_off"
X#define BLOCK_EVENT_ON_STR					"block_event_on"
X#define BLOCK_EVENT_OFF_STR					"block_event_off"
X#define START_REQUEST_COUNT_STR				"startrequestcount"
X#define STOP_REQUEST_COUNT_STR				"stoprequestcount"
X#define CLEAR_REQUEST_COUNT_STR				"clearrequestcount"
X#define PRINT_REQUEST_COUNT_STR				"printrequestcount"
X#define PRINT_ZERO_REQUEST_COUNT_STR		"printzerorequestcount"
X#define START_EVENT_COUNT_STR				"starteventcount"
X#define STOP_EVENT_COUNT_STR				"stopeventcount"
X#define CLEAR_EVENT_COUNT_STR				"cleareventcount"
X#define PRINT_EVENT_COUNT_STR				"printeventcount"
X#define PRINT_ZERO_EVENT_COUNT_STR			"printzeroeventcount"
X#define START_ERROR_COUNT_STR				"starterrorcount"
X#define STOP_ERROR_COUNT_STR				"stoperrorcount"
X#define CLEAR_ERROR_COUNT_STR				"clearerrorcount"
X#define PRINT_ERROR_COUNT_STR				"printerrorcount"
X#define PRINT_ZERO_ERROR_COUNT_STR			"printzeroerrorcount"
X#define REQUEST_MONITORING_ON_STR			"request_monitoring_on"
X#define REQUEST_MONITORING_OFF_STR			"request_monitoring_off"
X#define EVENT_MONITORING_ON_STR				"event_monitoring_on"
X#define EVENT_MONITORING_OFF_STR			"event_monitoring_off"
X#define REQUEST_BLOCKING_ON_STR				"request_blocking_on"
X#define REQUEST_BLOCKING_OFF_STR			"request_blocking_off"
X#define EVENT_BLOCKING_ON_STR				"event_blocking_on"
X#define EVENT_BLOCKING_OFF_STR				"event_blocking_off"
X#define QUIT_STR							"quit"
X#define HELP_STR							"help"
X
X#define Strleneq(a,b) Strneq(a, b, strlen(b))
X
Xstatic void
XReadStdin(private_data)
X	Pointer				private_data;
X{
X	int					fd = (int)private_data;
X	char				buf[2048];
X	char				*ptr;
X	int					n;
X
X	enterprocedure("ReadStdin");
X	n = read(fd, buf, 2048);
X	if (n == 0)
X	{
X		fprintf(stdout, "EOF on stdin\n");
X		exit(0);
X	}
X	if (n < 0)
X	{
X		fprintf(stdout, "Error reading stdin\n");
X		exit(0);
X	}
X
X	buf[n] = '\0';
X	ptr = buf;
X	while (*ptr == ' ' || *ptr == '\t')
X		ptr++;
X	if (*ptr != '\0')
X	{
X		if (Strleneq(ptr, REQUEST_VERBOSE_STR))
X			RequestVerbose = atoi(ptr + strlen(REQUEST_VERBOSE_STR));
X		else if (Strleneq(ptr, EVENT_VERBOSE_STR))
X			EventVerbose = atoi(ptr + strlen(EVENT_VERBOSE_STR));
X		else if (Strleneq(ptr, REPLY_VERBOSE_STR))
X			ReplyVerbose = atoi(ptr + strlen(REPLY_VERBOSE_STR));
X		else if (Strleneq(ptr, ERROR_VERBOSE_STR))
X			ErrorVerbose = atoi(ptr + strlen(ERROR_VERBOSE_STR));
X		else if (Strleneq(ptr, MONITOR_REQUEST_ON_STR))
X			VerboseRequest[atoi(ptr + strlen(MONITOR_REQUEST_ON_STR))] = True;
X		else if (Strleneq(ptr, MONITOR_REQUEST_OFF_STR))
X			VerboseRequest[atoi(ptr + strlen(MONITOR_REQUEST_OFF_STR))] = False;
X		else if (Strleneq(ptr, MONITOR_EVENT_ON_STR))
X			VerboseEvent[atoi(ptr + strlen(MONITOR_EVENT_ON_STR))] = True;
X		else if (Strleneq(ptr, MONITOR_EVENT_OFF_STR))
X			VerboseEvent[atoi(ptr + strlen(MONITOR_EVENT_OFF_STR))] = False;
X		else if (Strleneq(ptr, REQUEST_MONITORING_ON_STR))
X			MonitoringRequests = True;
X		else if (Strleneq(ptr, REQUEST_MONITORING_OFF_STR))
X			MonitoringRequests = False;
X		else if (Strleneq(ptr, EVENT_MONITORING_ON_STR))
X			MonitoringEvents = True;
X		else if (Strleneq(ptr, EVENT_MONITORING_OFF_STR))
X			MonitoringEvents = False;
X		else if (Strleneq(ptr, REQUEST_BLOCKING_ON_STR))
X			BlockingRequests = True;
X		else if (Strleneq(ptr, REQUEST_BLOCKING_OFF_STR))
X			BlockingRequests = False;
X		else if (Strleneq(ptr, EVENT_BLOCKING_ON_STR))
X			BlockingEvents = True;
X		else if (Strleneq(ptr, EVENT_BLOCKING_OFF_STR))
X			BlockingEvents = False;
X		else if (Strleneq(ptr, SELECTED_REQUEST_VERBOSE_STR))
X			SelectedRequestVerbose =
X				atoi(ptr +strlen(SELECTED_REQUEST_VERBOSE_STR));
X		else if (Strleneq(ptr, SELECTED_EVENT_VERBOSE_STR))
X			SelectedEventVerbose =
X				atoi(ptr + strlen(SELECTED_EVENT_VERBOSE_STR));
X		else if (Strleneq(ptr, BLOCK_REQUEST_ON_STR))
X			BlockRequest[atoi(ptr + strlen(BLOCK_REQUEST_ON_STR))] = True;
X		else if (Strleneq(ptr, BLOCK_REQUEST_OFF_STR))
X			BlockRequest[atoi(ptr + strlen(BLOCK_REQUEST_OFF_STR))] = False;
X		else if (Strleneq(ptr, BLOCK_EVENT_ON_STR))
X			BlockEvent[atoi(ptr + strlen(BLOCK_EVENT_ON_STR))] = True;
X		else if (Strleneq(ptr, BLOCK_EVENT_OFF_STR))
X			BlockEvent[atoi(ptr + strlen(BLOCK_EVENT_OFF_STR))] = False;
X		else if (Strleneq(ptr, START_REQUEST_COUNT_STR))
X			StartRequestCount();
X		else if (Strleneq(ptr, STOP_REQUEST_COUNT_STR))
X			EndRequestCount();
X		else if (Strleneq(ptr, CLEAR_REQUEST_COUNT_STR))
X			ClearRequestCount();
X		else if (Strleneq(ptr, PRINT_REQUEST_COUNT_STR))
X			PrintRequestCounts();
X		else if (Strleneq(ptr, PRINT_ZERO_REQUEST_COUNT_STR))
X			PrintZeroRequestCounts();
X		else if (Strleneq(ptr, START_EVENT_COUNT_STR))
X			StartEventCount();
X		else if (Strleneq(ptr, STOP_EVENT_COUNT_STR))
X			EndEventCount();
X		else if (Strleneq(ptr, CLEAR_EVENT_COUNT_STR))
X			ClearEventCount();
X		else if (Strleneq(ptr, PRINT_EVENT_COUNT_STR))
X			PrintEventCounts();
X		else if (Strleneq(ptr, PRINT_ZERO_EVENT_COUNT_STR))
X			PrintZeroEventCounts();
X		else if (Strleneq(ptr, START_ERROR_COUNT_STR))
X			StartErrorCount();
X		else if (Strleneq(ptr, STOP_ERROR_COUNT_STR))
X			EndErrorCount();
X		else if (Strleneq(ptr, CLEAR_ERROR_COUNT_STR))
X			ClearErrorCount();
X		else if (Strleneq(ptr, PRINT_ERROR_COUNT_STR))
X			PrintErrorCounts();
X		else if (Strleneq(ptr, PRINT_ZERO_ERROR_COUNT_STR))
X			PrintZeroErrorCounts();
X		else if (Strleneq(ptr, QUIT_STR))
X			exit(0);
X		else if (Strleneq(ptr, HELP_STR))
X		{
X			fprintf(stdout, "%s <verbose_level>\n", REQUEST_VERBOSE_STR);
X			fprintf(stdout, "%s <verbose_level>\n", EVENT_VERBOSE_STR);
X			fprintf(stdout, "%s <verbose_level>\n", REPLY_VERBOSE_STR);
X			fprintf(stdout, "%s <verbose_level>\n", ERROR_VERBOSE_STR);
X			fprintf(stdout, "%s <verbose_request_number>\n",
X												MONITOR_REQUEST_ON_STR);
X			fprintf(stdout, "%s <verbose_request_number>\n",
X												MONITOR_REQUEST_OFF_STR);
X			fprintf(stdout, "%s <verbose_event_number>\n",
X												MONITOR_EVENT_ON_STR);
X			fprintf(stdout, "%s <verbose_event_number>\n",
X												MONITOR_EVENT_OFF_STR);
X			fprintf(stdout, "%s <selected_request_verboseness>\n",
X												SELECTED_REQUEST_VERBOSE_STR);
X			fprintf(stdout, "%s <selected_event_verboseness>\n",
X												SELECTED_EVENT_VERBOSE_STR);
X			fprintf(stdout, "%s <block_request_number>\n",BLOCK_REQUEST_ON_STR);
X			fprintf(stdout,"%s <block_request_number>\n",BLOCK_REQUEST_OFF_STR);
X			fprintf(stdout, "%s <block_event_number>\n", BLOCK_EVENT_ON_STR);
X			fprintf(stdout, "%s <block_event_number>\n", BLOCK_EVENT_OFF_STR);
X
X			fprintf(stdout, "%s\n", START_REQUEST_COUNT_STR);
X			fprintf(stdout, "%s\n", STOP_REQUEST_COUNT_STR);
X			fprintf(stdout, "%s\n", CLEAR_REQUEST_COUNT_STR);
X			fprintf(stdout, "%s\n", PRINT_REQUEST_COUNT_STR);
X			fprintf(stdout, "%s\n", PRINT_ZERO_REQUEST_COUNT_STR);
X			fprintf(stdout, "%s\n", START_EVENT_COUNT_STR);
X			fprintf(stdout, "%s\n", STOP_EVENT_COUNT_STR);
X			fprintf(stdout, "%s\n", CLEAR_EVENT_COUNT_STR);
X			fprintf(stdout, "%s\n", PRINT_EVENT_COUNT_STR);
X			fprintf(stdout, "%s\n", PRINT_ZERO_EVENT_COUNT_STR);
X			fprintf(stdout, "%s\n", START_ERROR_COUNT_STR);
X			fprintf(stdout, "%s\n", STOP_ERROR_COUNT_STR);
X			fprintf(stdout, "%s\n", CLEAR_ERROR_COUNT_STR);
X			fprintf(stdout, "%s\n", PRINT_ERROR_COUNT_STR);
X			fprintf(stdout, "%s\n", PRINT_ZERO_ERROR_COUNT_STR);
X			fprintf(stdout, "%s\n", QUIT_STR);
X			fprintf(stdout, "%s\n", HELP_STR);
X		}
X		else
X			fprintf
X			(
X				stdout, "illegal command: %s\n\"help\" to get help\n", ptr
X			);
X	}
X}
X
X/*
X * NewConnection:
X * 
X * Create New Connection to a client program and to Server.
X */
Xstatic void
XNewConnection(private_data)
X	Pointer				private_data;
X{
X	int					XPort = (int)private_data;
X	Client				*client;
X	Server				*server;
X	int					fd;
X
X	client = Tmalloc(Client);
X	appendToList(&client_list, (Pointer)client);
X	fd = ConnectToClient(XPort);
X	client->fdd = UsingFD(fd, DataFromClient, (Pointer)client);
X	client->fdd->fd = fd;
X	StartClientConnection(client);
X
X	initList(&client->server_list);
X	server = Tmalloc(Server);
X	appendToList(&client->server_list, (Pointer)server);
X	fd = ConnectToServer(ServerHostName);
X	server->fdd = UsingFD(fd, DataFromServer, (Pointer)server);
X	server->fdd->fd = fd;
X	server->client = client;
X	StartServerConnection(server);
X
X	ClientNumber += 1;
X	client->ClientNumber = ClientNumber;
X}
X
Xstatic void
XDataFromClient(private_data)
X	Pointer					private_data;
X{
X	Client					*client = (Client *)private_data;
X	Server					*server;
X
X	server = (Server *)(TopOfList(&client->server_list));
X	if (!ReadAndProcessData(private_data, client->fdd, server->fdd))
X		CloseConnection(client);
X}
X
Xstatic void
XDataFromServer(private_data)
X	Pointer					private_data;
X{
X	Server					*server = (Server *)private_data;
X	Client					*client = server->client;
X
X	if (!ReadAndProcessData(private_data, server->fdd, client->fdd))
X		CloseConnection(client);
X}
X
X/*
X * ReadAndProcessData:
X * 
X * Read as much as we can and then loop as long as we have enough
X * bytes to do anything.
X * 
X * In each cycle check if we have enough bytes (saved or in the newly read
X * buffer) to do something.  If so, we want the bytes to be grouped
X * together into one contiguous block of bytes.  We have three cases:
X * 
X * (1) num_Saved == 0; so all needed bytes are in the read buffer.
X * 
X * (2) num_Saved >= num_Needed; in this case all needed
X * bytes are in the save buffer and we will not need to copy any extra
X * bytes from the read buffer into the save buffer.
X * 
X * (3) 0 < num_Saved < num_Needed; so some bytes are in
X * the save buffer and others are in the read buffer.  In this case we
X * need to copy some of the bytes from the read buffer to the save buffer
X * to get as many bytes as we need, then use these bytes.  First determine
X * the number of bytes we need to transfer; then transfer them and remove
X * them from the read buffer.  (There may be additional requests in the
X * read buffer - we'll deal with them next cycle.)
X * 
X * At this stage, we have a pointer to a contiguous block of
X * num_Needed bytes that we should process.  The type of
X * processing depends upon the state we are in, given in the
X * ByteProcessing field of the FDDescriptor structure pointed to by
X * read_fdd.  The processing routine returns the number of bytes that it
X * actually used.
X * 
X * The number of bytes that were actually used is normally (but not
X * always) the number of bytes needed.  Discard the bytes that were
X * actually used, not the bytes that were needed.  The number of used
X * bytes must be less than or equal to the number of needed bytes.  If
X * there were no saved bytes, then the bytes that were used must have been
X * in the read buffer so just modify the buffer pointer.  Otherwise call
X * RemoveSavedBytes.
X * 
X * After leaving the loop, if there are still some bytes left in the read
X * buffer append the newly read bytes to the save buffer.
X *
X * Return False if we reached end-of-file on read.
X */
X
Xstatic Bool
XReadAndProcessData(private_data, read_fdd, write_fdd)
X	Pointer					private_data;
X	FDDescriptor			*read_fdd;
X	FDDescriptor			*write_fdd;
X{
X	Buffer					*inbuffer = &read_fdd->inBuffer;
X	Buffer					*outbuffer = &write_fdd->outBuffer;
X	int						fd = read_fdd->fd;
X	char					read_buf_block[2048];
X	char					*read_buf = read_buf_block;
X	int						num_read;
X	char					*process_buf;
X	int						NumberofUsedBytes;
X	int						BytesToSave;
X
X	num_read = read(fd, read_buf, 2048);
X	if (num_read < 0)
X	{
X		perror("read error");
X		if (errno == EWOULDBLOCK)
X			panic("ReadAndProcessData: read would block (not implemented)");
X		if (errno == EINTR)
X			panic("ReadAndProcessData: read interrupted (not implemented)");
X	}
X	if (num_read == 0)
X	{
X		if (ErrorVerbose > 1)
X			fprintf(stdout, "EOF\n");
X		return False;
X	}
X
X	littleEndian = read_fdd->littleEndian;
X	while (inbuffer->num_Saved + num_read >= inbuffer->num_Needed)
X	{
X		if (inbuffer->num_Saved == 0)
X			process_buf = read_buf;
X		else
X		{
X			if (inbuffer->num_Saved < inbuffer->num_Needed)
X			{
X				BytesToSave = inbuffer->num_Needed - inbuffer->num_Saved;
X				SaveBytes(inbuffer, read_buf, BytesToSave);
X				read_buf += BytesToSave;
X				num_read -= BytesToSave;
X			}
X			process_buf = inbuffer->data;
X		}
X		ignore_bytes = False;
X		NumberofUsedBytes = (*read_fdd->ByteProcessing)
X		(
X			private_data, process_buf, inbuffer->num_Needed
X		);
X		if (NumberofUsedBytes > 0)
X		{
X			if (!ignore_bytes)
X				SaveBytes(outbuffer, process_buf, NumberofUsedBytes);
X			if (inbuffer->num_Saved > 0)
X				RemoveSavedBytes(inbuffer, NumberofUsedBytes);
X			else
X			{
X				read_buf += NumberofUsedBytes;
X				num_read -= NumberofUsedBytes;
X			}
X		}
X	}
X	if (num_read > 0)
X		SaveBytes(inbuffer, read_buf, num_read);
X	return True;
X}
X
X/*
X * We will need to save bytes until we get a complete request to
X * interpret.  The following procedures provide this ability.
X */
X
Xstatic void
XSaveBytes(buffer, buf, n)
X	Buffer					*buffer;
X	char					*buf;
X	long					n;
X{
X	long					new_size;
X	char					*new_buf;
X
X	/* check if there is enough space to hold the bytes we want */
X	if (buffer->num_Saved + n > buffer->BlockSize)
X		{
X			/* not enough room so far; malloc more space and copy */
X			new_size = (buffer->num_Saved + n + 1);
X			new_buf = (char *)malloc(new_size);
X			bcopy(buffer->data, new_buf, buffer->BlockSize);
X			if (buffer->BlockSize > 0)
X				Tfree(buffer->data);
X			buffer->data = new_buf;
X			buffer->BlockSize = new_size;
X		}
X
X	/* now copy the new bytes onto the end of the old bytes */
X	bcopy(buf, (buffer->data + buffer->num_Saved), n);
X	buffer->num_Saved += n;
X}
X
Xstatic void
XRemoveSavedBytes(buffer, n)
X	Buffer					*buffer;
X	int						n;
X{
X	/* check if all bytes are being removed -- easiest case */
X	if (buffer->num_Saved <= n)
X		buffer->num_Saved = 0;
X	else if (n != 0)
X	{
X		/* not all bytes are being removed -- shift the remaining ones down  */
X		register char  *p = buffer->data;
X		register char  *q = buffer->data + n;
X		register int   i = buffer->num_Saved - n;
X		while (i-- > 0)
X			*p++ = *q++;
X		buffer->num_Saved -= n;
X	}
X}
X
Xstatic int
XConnectToClient(ConnectionSocket)
X		int ConnectionSocket;
X{
X	int                   ON = 1;         /* used in ioctl */
X	int ClientFD;
X	struct sockaddr_in  from;
X	int    len = sizeof (from);
X
X	ClientFD = accept(ConnectionSocket, (struct sockaddr *)&from, &len);
X	debug(4,(stderr, "Connect To Client: FD %d\n", ClientFD));
X	if (ClientFD < 0 && errno == EWOULDBLOCK)
X		{
X			debug(4,(stderr, "Almost blocked accepting FD %d\n", ClientFD));
X			panic("Can't connect to Client");
X		}
X	if (ClientFD < 0)
X		{
X			debug(4,(stderr, "ConnectToClient: error %d\n", errno));
X			panic("Can't connect to Client");
X		}
X
X	ioctl(ClientFD, FIOCLEX, 0);
X	ioctl(ClientFD, FIONBIO, &ON);
X	return(ClientFD);
X}
X
Xstatic int
XConnectToServer(hostName)
X	char *hostName;
X{
X	int ServerFD;
X	struct sockaddr_in  sin;
X	struct hostent *hp;
X
X	enterprocedure("ConnectToServer");
X
X	/* establish a socket to the name server for this host */
X	bzero((char *)&sin, sizeof(sin));
X	ServerFD = socket(AF_INET, SOCK_STREAM, 0);
X	if (ServerFD < 0)
X		{
X			perror("socket() to Server failed");
X			debug(1,(stderr, "socket failed\n"));
X			panic("Can't open connection to Server");
X		}
X	(void) setsockopt(ServerFD, SOL_SOCKET, SO_REUSEADDR,  (char *) NULL, 0);
X	(void) setsockopt(ServerFD, SOL_SOCKET, SO_USELOOPBACK,(char *) NULL, 0);
X#ifdef SO_DONTLINGER
X	(void) setsockopt(ServerFD, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
X#endif
X
X	debug(4,(stderr, "try to connect on %s\n", hostName));
X
X	hp = gethostbyname(hostName);
X	if (hp == 0)
X		{
X			perror("gethostbyname failed");
X			debug(1,(stderr, "gethostbyname failed for %s\n", hostName));
X			panic("Can't open connection to Server");
X		}
X
X	sin.sin_family = AF_INET;
X	bcopy((char *)hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
X	sin.sin_port = htons (GetServerport());
X
X	/* ******************************************************** */
X	/* try to connect to Server */
X
X	if (connect(ServerFD, (struct sockaddr *)&sin, sizeof(sin)) < 0)
X		{
X			debug(4,(stderr, "connect returns errno of %d\n", errno));
X			if (errno != 0)
X				perror("connect");
X			switch (errno)
X				{
X				case ECONNREFUSED:
X					/* experience says this is because there is no Server
X						to connect to */
X					close(ServerFD);
X					debug(1,(stderr, "No Server\n"));
X					panic("Can't open connection to Server");
X				default:
X					close(ServerFD);
X					panic("Can't open connection to Server");
X				}
X		}
X
X	debug(4,(stderr, "Connect To Server: FD %d\n", ServerFD));
X	return(ServerFD);
X}
X
Xstatic char*
XOfficialName(name)
Xchar *name;
X{
X	struct hostent *HostEntry;
X
X	HostEntry = gethostbyname(name);
X	if (HostEntry == NULL)
X		{
X			perror("gethostbyname");
X			exit(-1);
X		}
X	debug(4,(stderr, "Official name of %s is %s\n", name, HostEntry->h_name));
X	return(HostEntry->h_name);
X}
X
Xstatic void
XSignalURG()
X{
X	debug(1,(stderr, "==> SIGURG received\n"));
X}
X
Xstatic void
XSignalPIPE()
X{
X	debug(1,(stderr, "==> SIGPIPE received\n"));
X}
X
Xstatic void
XSignalINT()
X{
X	debug(1,(stderr, "==> SIGINT received\n"));
X	exit(1);
X}
X
Xstatic void
XSignalQUIT()
X{
X	debug(1,(stderr, "==> SIGQUIT received\n"));
X	exit(1);
X}
X
Xstatic void
XSignalTERM()
X{
X	debug(1,(stderr, "==> SIGTERM received\n"));
X	exit(1);
X}
X
Xstatic void
XSignalTSTP()
X{
X	debug(1,(stderr, "==> SIGTSTP received\n"));
X}
X
Xstatic void
XSignalCONT()
X{
X	debug(1,(stderr, "==> SIGCONT received\n"));
X}
X
XGlobal void
Xenterprocedure(s)
X		char   *s;
X{
X	debug(2,(stderr, "-> %s\n", s));
X}
X
XGlobal void
Xpanic(s)
X		char   *s;
X{
X	fprintf(stderr, "%s\n", s);
X	exit(1);
X}
SHAR_EOF
$TOUCH -am 0903162990 main.c &&
chmod 0664 main.c ||
echo "restore of main.c failed"
set `wc -c main.c`;Wc_c=$1
if test "$Wc_c" != "30426"; then
	echo original size 30426, current size $Wc_c
fi
fi
# ============= prtype.c ==============
if test X"$1" != X"-c" -a -f 'prtype.c'; then
	echo "File already exists: skipping 'prtype.c'"
else
echo "x - extracting prtype.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > prtype.c &&
X/*
X * Project: XMON - An X protocol monitor
X * 
X * File: prtype.c
X * 
X * Description: Type Printing for X11 protocol
X * 
X * For each of the types we need a way to print that type.  Types are of
X * varieties:
X * 
X * (1) BUILTIN -- we have a separate routine to interpret and print each
X * built-in type.
X * 
X * (2) ENUMERATED, SET -- we have one routine which prints, given the data
X * and the list of values.
X * 
X * (3) RECORDS -- a separate routine for each to print each field.
X */
X
X#include "common.h"
X
X#include "xmond.h"
X#include "x11.h"
X
X/*
X * we use indentation for two purposes:
X * 
X * (1) To show substructure of records inside records ...
X * 
X * (2) To separate the bytes from the client (on the left) from those from
X * the server (on the right).
X * 
X * Each indention level is one tab (8 spaces).
X */
X#define MaxIndent 10
X
X#define NumberofAtoms 68
X#define MAXline 78
X
X/* function prototypes: */
X/* prtype.c: */
Xstatic char *printrep P((unsigned short c ));
Xstatic short SizeofLeader P((void ));
X
X/* end function prototypes */
X
Xextern int					CurrentVerbose;
Xextern int					debuglevel;
X
Xstatic char Leader[MaxIndent + 1];
Xstatic short    CurrentLevel = 0;
X
Xstatic char   *AtomTable[NumberofAtoms + 1] =
X{
X	"NONE", "PRIMARY", "SECONDARY", "ARC", "ATOM", "BITMAP", "CARDINAL",
X	"COLORMAP", "CURSOR", "CUT_BUFFER0", "CUT_BUFFER1", "CUT_BUFFER2",
X	"CUT_BUFFER3", "CUT_BUFFER4", "CUT_BUFFER5", "CUT_BUFFER6",
X	"CUT_BUFFER7", "DRAWABLE", "FONT", "INTEGER", "PIXMAP", "POINT",
X	"RECTANGLE", "RESOURCE_MANAGER", "RGB_COLOR_MAP", "RGB_BEST_MAP",
X	"RGB_BLUE_MAP", "RGB_DEFAULT_MAP", "RGB_GRAY_MAP", "RGB_GREEN_MAP",
X	"RGB_RED_MAP", "STRING", "VISUALID", "WINDOW", "WM_COMMAND",
X	"WM_HINTS", "WM_CLIENT_MACHINE", "WM_ICON_NAME", "WM_ICON_SIZE",
X	"WM_NAME", "WM_NORMAL_HINTS", "WM_SIZE_HINTS", "WM_ZOOM_HINTS",
X	"MIN_SPACE", "NORM_SPACE", "MAX_SPACE", "END_SPACE", "SUPERSCRIPT_X",
X	"SUPERSCRIPT_Y", "SUBSCRIPT_X", "SUBSCRIPT_Y", "UNDERLINE_POSITION",
X	"UNDERLINE_THICKNESS", "STRIKEOUT_ASCENT", "STRIKEOUT_DESCENT",
X	"ITALIC_ANGLE", "X_HEIGHT", "QUAD_WIDTH", "WEIGHT", "POINT_SIZE",
X	"RESOLUTION", "COPYRIGHT", "NOTICE", "FONT_NAME", "FAMILY_NAME",
X	"FULL_NAME", "CAP_HEIGHT", "WM_CLASS", "WM_TRANSIENT_FOR"
X	};
X
X/*
X * printrep:
X * 
X * print representation of a character for debugging
X */
Xstatic char*
Xprintrep (c)
X		unsigned short  c;
X{
X	static char pr[8];
X
X	if (c < 32)
X		{
X			/* control characters */
X			pr[0] = '^';
X			pr[1] = c + 64;
X			pr[2] = '\0';
X		}
X	else if (c < 127)
X			{
X				/* printing characters */
X				pr[0] = c;
X				pr[1] = '\0';
X			}
X		else if (c == 127)
X				return("<del>");
X			else if (c <= 0377)
X					{
X						/* upper 128 codes from 128 to 255;  print as \ooo - octal  */
X						pr[0] = '\\';
X						pr[3] = '0' + (c & 7);
X						c = c >> 3;
X						pr[2] = '0' + (c & 7);
X						c = c >> 3;
X						pr[1] = '0' + (c & 3);
X						pr[4] = '\0';
X					}
X				else
X					{
X						/* very large number -- print as 0xffff - 4 digit hex */
X						sprintf(pr, "0x%04x", c);
X					}
X	return(pr);
X}
X
XGlobal void
XSetIndentLevel(which)
X		short   which;
X{
X	short   i;
X
X	if (which > MaxIndent)
X		which = MaxIndent;
X	if (which < 0)
X		which = 0;
X	if (which == CurrentLevel)
X		return;
X
X	/* set the indent level to <which> */
X	/* -> set the Print Leader to <which> tabs */
X	for (i = 0; i < which; i++)
X		Leader[i] = '\t';
X	Leader[which] = '\0';
X	CurrentLevel = which;
X}
X
XGlobal void
XModifyIndentLevel(amount)
X		short   amount;
X{
X	SetIndentLevel(CurrentLevel + amount);
X}
X
Xstatic short
XSizeofLeader ()
X{
X	return (CurrentLevel * 8);
X}
X
X/*
X * DumpItem:
X * 
X * if we want verbose enough output, we will dump the buffer in hex
X */
XGlobal void
XDumpItem(name, fd, buf, n)
X		char   *name;
X		int      fd;
X		unsigned char *buf;
X		long    n;
X{
X	if (n == 0)
X		return;
X
X	fprintf(stdout, "%s%20s (fd %d): ", Leader, name, fd);
X
X	DumpHexBuffer(buf, n);
X	fprintf(stdout, "\n");
X}
X
XGlobal void
XPrintINT8(buf)
X		unsigned char *buf;
X{
X	/* print a INT8 -- 8-bit signed integer */
X	short   n = IByte (buf);
X	if (n > 127)
X		n = 256 - n;
X	fprintf(stdout, "%d", n);
X}
X
XGlobal void
XPrintINT16(buf)
X		unsigned char *buf;
X{
X	/* print a INT16 -- 16-bit signed integer */
X	long    n = IShort (buf);
X	if (n > 32767)
X		n = 65536 - n;
X	fprintf(stdout, "%d", n);
X}
X
XGlobal void
XPrintINT32(buf)
X		unsigned char *buf;
X{
X	/* print a INT32 -- 32-bit signed integer */
X	long    n = ILong (buf);
X	fprintf(stdout, "%d", n);
X}
X
XGlobal void
XPrintCARD8(buf)
X		unsigned char *buf;
X{
X	/* print a CARD8 -- 8-bit unsigned integer */
X	short   n = IByte (buf);
X	fprintf(stdout, "%02x", (unsigned)(n & 0xff));
X}
X
XGlobal void
XPrintCARD16(buf)
X		unsigned char *buf;
X{
X	/* print a CARD16 -- 16-bit unsigned integer */
X	unsigned long   n = IShort (buf);
X	fprintf(stdout, "%04x", (unsigned)(n & 0xffff));
X}
X
XGlobal int
XPrintCARD32(buf)
X		unsigned char *buf;
X{
X	/* print a CARD32 -- 32-bit unsigned integer */
X	unsigned long   n = ILong (buf);
X	fprintf(stdout, "%08x", n);
X	return(4);
X}
X
XGlobal int
XPrintBYTE(buf)
X		unsigned char *buf;
X{
X	/* print a BYTE -- 8-bit value */
X	short   n = IByte (buf);
X	fprintf(stdout, "%02x", n);
X	return(1);
X}
X
XGlobal int
XPrintCHAR8(buf)
X		unsigned char *buf;
X{
X	/* print a CHAR8 -- 8-bit character */
X	unsigned short   n = IByte (buf);
X	fprintf(stdout, "%s", printrep(n));
X	return(1);
X}
X
XGlobal int
XPrintSTRING16(buf)
X		unsigned char *buf;
X{
X	/* print a CHAR16 -- 16-bit character */
X	unsigned short   n = IShort (buf);
X	fprintf(stdout, "%s", printrep(n));
X	return(1);
X}
X
XGlobal int
XPrintSTR(buf)
X		unsigned char *buf;
X{
X	/* STR have the length (1 byte) then a string of CHAR8 */
X	short   n;
X	short   i;
X
X	n = IByte(buf++);
X	for (i = 0; i < n; i++)
X		fprintf(stdout, "%s", printrep(buf[i]));
X	return(n+1);
X}
X
XGlobal int
XPrintWINDOW(buf)
X		unsigned char *buf;
X{
X	/* print a WINDOW -- CARD32  plus 0 = None */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "None");
X	else
X		fprintf(stdout, "WIN %08x", n);
X	return(4);
X}
X
XGlobal void
XPrintWINDOWD(buf)
X		unsigned char *buf;
X{
X	/* print a WINDOWD -- CARD32  plus 0 = PointerWindow, 1 = InputFocus */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "PointerWindow");
X	else if (n == 1)
X			fprintf(stdout, "InputFocus");
X		else
X			PrintWINDOW(buf);
X}
X
XGlobal void
XPrintWINDOWNR(buf)
X		unsigned char *buf;
X{
X	/* print a WINDOWNR -- CARD32  plus 0 = None, 1 = PointerRoot */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "None");
X	else if (n == 1)
X			fprintf(stdout, "PointerRoot");
X		else
X			PrintWINDOW(buf);
X}
X
X
XGlobal void
XPrintPIXMAP(buf)
X		unsigned char *buf;
X{
X	/* print a PIXMAP -- CARD32  plus 0 = None */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "None");
X	else
X		fprintf(stdout, "PXM %08x", n);
X}
X
XGlobal void
XPrintPIXMAPNPR(buf)
X		unsigned char *buf;
X{
X	/* print a PIXMAPNPR -- CARD32  plus 0 = None, 1 = ParentRelative */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "None");
X	else if (n == 1)
X			fprintf(stdout, "ParentRelative");
X		else
X			PrintPIXMAP(buf);
X}
X
XGlobal void
XPrintPIXMAPC(buf)
X		unsigned char *buf;
X{
X	/* print a PIXMAPC -- CARD32  plus 0 = CopyFromParent */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "CopyFromParent");
X	else
X		PrintPIXMAP(buf);
X}
X
X
XGlobal void
XPrintCURSOR(buf)
X		unsigned char *buf;
X{
X	/* print a CURSOR -- CARD32  plus 0 = None */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "None");
X	else
X		fprintf(stdout, "CUR %08x", n);
X}
X
X
XGlobal void
XPrintFONT(buf)
X		unsigned char *buf;
X{
X	/* print a FONT -- CARD32  plus 0 = None */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "None");
X	else
X		fprintf(stdout, "FNT %08x", n);
X}
X
X
XGlobal void
XPrintGCONTEXT(buf)
X		unsigned char *buf;
X{
X	/* print a GCONTEXT -- CARD32 */
X	long    n = ILong (buf);
X	fprintf(stdout, "GXC %08x", n);
X}
X
X
XGlobal int
XPrintCOLORMAP(buf)
X		unsigned char *buf;
X{
X	/* print a COLORMAP -- CARD32 plus 0 = None */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "None");
X	else
X		fprintf(stdout, "CMP %08x", n);
X	return(4);
X}
X
XGlobal void
XPrintCOLORMAPC(buf)
X		unsigned char *buf;
X{
X	/* print a COLORMAPC -- CARD32 plus 0 = CopyFromParent */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "CopyFromParent");
X	else
X		PrintCOLORMAP(buf);
X}
X
X
XGlobal void
XPrintDRAWABLE(buf)
X		unsigned char *buf;
X{
X	/* print a DRAWABLE -- CARD32 */
X	long    n = ILong (buf);
X	fprintf(stdout, "DWB %08x", n);
X}
X
XGlobal void
XPrintFONTABLE(buf)
X		unsigned char *buf;
X{
X	/* print a FONTABLE -- CARD32 */
X	long    n = ILong (buf);
X	fprintf(stdout, "FTB %08x", n);
X}
X
X/*
X * For atoms, we print the built-in atoms.  We could expand to printing
X *	the user defined ones, too.
X */
X
XGlobal int
XPrintATOM(buf)
X		unsigned char *buf;
X{
X	/* print a ATOM -- CARD32 plus 0 = None */
X	long    n = ILong (buf);
X	if (0 <= n && n <= NumberofAtoms)
X		fprintf(stdout, "<%s>", AtomTable[n]);
X	else
X		fprintf(stdout, "ATM %08x", n);
X	return(4);
X}
X
XGlobal void
XPrintATOMT(buf)
X		unsigned char *buf;
X{
X	/* print a ATOMT -- CARD32 plus 0 = AnyPropertyType */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "AnyPropertyType");
X	else
X		PrintATOM(buf);
X}
X
X
XGlobal void
XPrintVISUALID(buf)
X		unsigned char *buf;
X{
X	/* print a VISUALID -- CARD32 plus 0 = None */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "None");
X	else
X		fprintf(stdout, "VIS %08x", n);
X}
X
XGlobal void
XPrintVISUALIDC(buf)
X		unsigned char *buf;
X{
X	/* print a VISUALIDC -- CARD32 plus 0 = CopyFromParent */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "CopyFromParent");
X	else
X		PrintVISUALID(buf);
X}
X
X
XGlobal void
XPrintTIMESTAMP(buf)
X		unsigned char *buf;
X{
X	/* print a TIMESTAMP -- CARD32 plus 0 as the current time */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "CurrentTime");
X	else
X		fprintf(stdout, "TIM %08x", n);
X}
X
X
XGlobal void
XPrintRESOURCEID(buf)
X		unsigned char *buf;
X{
X	/* print a RESOURCEID -- CARD32 plus 0 = AllTemporary */
X	long    n = ILong (buf);
X	if (n == 0)
X		fprintf(stdout, "AllTemporary");
X	else
X		fprintf(stdout, "RID %08x", n);
X}
X
X
XGlobal int
XPrintKEYSYM(buf)
X		unsigned char *buf;
X{
X	/* print a KEYSYM -- CARD32 */
X	long    n = ILong (buf);
X	fprintf(stdout, "KYS %08x", n);
X	return(4);
X}
X
XGlobal int
XPrintKEYCODE(buf)
X		unsigned char *buf;
X{
X	/* print a KEYCODE -- CARD8 */
X	unsigned short n = IByte (buf);
X	fprintf(stdout, "%d (%s)", n, printrep(n));
X	return(1);
X}
X
XGlobal void
XPrintKEYCODEA(buf)
X		unsigned char *buf;
X{
X	/* print a KEYCODEA -- CARD8 plus 0 = AnyKey */
X	long    n = IByte (buf);
X	if (n == 0)
X		fprintf(stdout, "AnyKey");
X	else
X		PrintKEYCODE(buf);
X}
X
X
XGlobal void
XPrintBUTTON(buf)
X		unsigned char *buf;
X{
X	/* print a BUTTON -- CARD8 */
X	unsigned short n = IByte (buf);
X	fprintf(stdout, "%d (%s)", n, printrep(n));
X}
X
XGlobal void
XPrintBUTTONA(buf)
X		unsigned char *buf;
X{
X	/* print a BUTTONA -- CARD8 plus 0 = AnyButton */
X	long    n = IByte (buf);
X	if (n == 0)
X		fprintf(stdout, "AnyButton");
X	else
X		PrintBUTTON(buf);
X}
X
X
X/*
X * PrintEVENTFORM:
X *
X * This is an interesting cheat -- we call DecodeEvent to print an event
X * should work, but its never been tried.
X */
XGlobal void
XPrintEVENTFORM(buf)
X		unsigned char *buf;
X{
X	/* print an EVENT_FORM -- event format */
X	fprintf(stdout, "PrintEVENTFORM: calling DecodeEvent with NULL server!\n");
X	DecodeEvent((Server *)NULL, buf, (long)-1);
X}
X
XGlobal void
XPrintENUMERATED(buf, length, ValueList)
X		unsigned char *buf;
X		short   length;
X		struct ValueListEntry  *ValueList;
X{
X	long   n;
X	struct ValueListEntry  *p;
X
X	if (length == 1)
X		n = IByte(buf);
X	else if (length == 2)
X			n = IShort(buf);
X		else
X			n = ILong(buf);
X
X	p = ValueList;
X	while (p != NULL && p->Value != n)
X		p = p->Next;
X
X	if (p != NULL)
X		fprintf(stdout, "%s", p->Name);
X	else
X		fprintf(stdout, "**INVALID** (%d)", n);
X}
X
XGlobal void
XPrintSET(buf, length, ValueList)
X		unsigned char *buf;
X		short   length;
X		struct ValueListEntry  *ValueList;
X{
X	unsigned long   n;
X	struct ValueListEntry  *p;
X	Bool MatchesAll = False;
X	Bool FoundOne = False;
X
X	if (length == 1)
X		n = IByte(buf);
X	else if (length == 2)
X			n = IShort(buf);
X		else
X			n = ILong(buf);
X
X	if (n != 0)
X		{
X			/* first check if the value matches ALL of the bits. */
X			MatchesAll = True;
X			for (p = ValueList; MatchesAll && (p != NULL); p = p->Next)
X				{
X					if ((p->Value & n) == 0)
X							MatchesAll = False;
X				}
X
X			if (!MatchesAll)
X				/* if it matches some but not all print only those it matches */
X				for (p = ValueList; p != NULL; p = p->Next)
X					{
X						if ((p->Value & n) != 0)
X							{
X								if (FoundOne)
X									fprintf(stdout, " | ");
X								fprintf(stdout, "%s", p->Name);
X								FoundOne = True;
X							}
X					}
X		}
X
X	if (MatchesAll)
X		fprintf(stdout, "<ALL>");
X	else if (!FoundOne)
X		fprintf(stdout, "0");
X}
X
XGlobal void
XPrintField(buf, start, length, FieldType, name)
X	unsigned char *buf;
X	short   start;
X	short   length;
X	short   FieldType;
X	char   *name;
X{
X	if (length == 0)
X		return;
X	if (CurrentVerbose <= 0)
X		return;
X
X	fprintf(stdout, "%s%20s: ", Leader, name);
X
X	if (debuglevel & 8)
X		DumpHexBuffer(&(buf[start]), (long)length);
X
X	switch (TD[FieldType].Type)
X	{
X	case BUILTIN:
X		(*TD[FieldType].PrintProc)(&buf[start]);
X		break;
X
X	case ENUMERATED:
X		PrintENUMERATED(&buf[start], length, TD[FieldType].ValueList);
X		break;
X
X	case SET:
X		PrintSET(&buf[start], length, TD[FieldType].ValueList);
X		break;
X
X	case RECORD:
X		ModifyIndentLevel(1);
X		fprintf(stdout, "\n");
X		if (CurrentVerbose < 3)
X			return;
X		(*TD[FieldType].PrintProc)(&buf[start]);
X		ModifyIndentLevel(-1);
X		break;
X	}
X	fprintf(stdout, "\n");
X	fflush(stdout);
X}
X
X/*
X * PrintList:
X *
X * Print a list of things.  The things are of type <ListType>.
X * They start at <buf>.  There are <number> things in the list
X */
XGlobal int
XPrintList(buf, number, ListType, name)
X		unsigned char *buf;
X		long   number;
X		short   ListType;
X		char   *name;
X{
X	long    n;
X	long    i;
X	long    sum;
X
X	if (number == 0)
X		return(0);
X
X	fprintf(stdout, "%s%20s: (%d)\n", Leader, name, number);
X	if (CurrentVerbose < 3)
X		return(0);
X
X	ModifyIndentLevel(1);
X	sum = 0;
X	for (i = 0; i < number; i++)
X		{
X			switch (TD[ListType].Type)
X				{
X										case BUILTIN:
X														n = (*TD[ListType].PrintProc)(buf);
X														break;
X										case RECORD:
X														n = (*TD[ListType].PrintProc)(buf);
X														break;
X										default:
X														fprintf(stdout, "**INVALID**");
X														n = 0;
X														break;
X				}
X			buf = buf + n;
X			sum = sum + n;
X			fprintf(stdout, "%s---\n", Leader);
X		}
X
X	ModifyIndentLevel(-1);
X	return(sum);
X}
X
X/*
X * PrintListSTR:
X *
X * Print a list of STRs.  Similar to PrintList
X * They start at <buf>.  There are <number> things in the list
X */
XGlobal void
XPrintListSTR(buf, number, name)
X		unsigned char *buf;
X		long   number;
X		char   *name;
X{
X	long    n;
X	long    i;
X	long    sum;
X
X	if (number == 0)
X		return;
X
X	fprintf(stdout, "%s%20s: (%d)\n", Leader, name, number);
X	if (CurrentVerbose < 3)
X		return;
X
X	ModifyIndentLevel(1);
X	sum = 0;
X	for (i = 0; i < number; i++)
X		{
X			fprintf(stdout, "%s", Leader);
X			n = PrintSTR(buf);
X			buf = buf + n;
X			sum = sum + n;
X			fprintf(stdout, "\n");
X		}
X
X	ModifyIndentLevel(-1);
X	return;
X}
X
XGlobal int
XPrintBytes(buf, number, name)
X		unsigned char   buf[];
X		long   number;
X		char   *name;
X{
X	/* print a list of BYTE -- 8-bit character */
X	long   i;
X	short   column;
X
X	if (number == 0)
X		return(0);
X
X	fprintf(stdout, "%s%20s: ", Leader, name);
X	column = SizeofLeader() + 25;
X	for (i = 0; i < number; i++)
X		{
X			if (column > 80)
X				{
X					if (CurrentVerbose < 3)
X						break;
X					fprintf(stdout, "\n%s%20s: ", Leader, "");
X					column = SizeofLeader() + 25;
X				}
X			fprintf(stdout, "%02x ",((unsigned int) buf[i]));
X			column += 3;
X		}
X	fprintf(stdout, "\n");
X
X	return((int)number);
X}
X
X/*
X * print a String of CHAR8 -- 8-bit characters
X */
XGlobal int
XPrintString8(buf, number, name)
X		unsigned char    buf[];
X		short   number;
X		char   *name;
X{
X	short   i;
X
X	if (number == 0)
X		return(0);
X
X	fprintf(stdout, "%s%20s: \"", Leader, name);
X	for (i = 0; i < number; i++)
X		fprintf(stdout, "%s", printrep(buf[i]));
X	fprintf(stdout, "\"\n");
X
X	return(number);
X}
X
X/*
X * print a String of CHAR16 -- 16-bit characters
X */
XGlobal int
XPrintString16(buf, number, name)
X		unsigned char    buf[];
X		short   number;
X		char   *name;
X{
X	short   i;
X	unsigned short   c;
X
X	if (number == 0)
X		return(0);
X
X	fprintf(stdout, "%s%20s: \"", Leader, name);
X	for (i = 0; i < number; i += 2)
X		{
X			c = IShort(&buf[i]);
X			fprintf(stdout, "%s", printrep(c));
X		}
X	fprintf(stdout, "\"\n");
X
X	return(number);
X}
X
X/*
X	A Value List is two things:
X
X	(1) A controlling bitmask.  For each one bit in the control,
X	a value is in the list.
X	(2) A list of values.
X*/
X
XGlobal void
XPrintValues(control, clength, ctype, values, name)
X		unsigned char   *control;
X		short   clength;
X		short   ctype;
X		unsigned char   *values;
X		char   *name;
X{
X	long    cmask;
X	struct ValueListEntry  *p;
X
X	/* first get the control mask */
X	if (clength == 1)
X		cmask = IByte(control);
X	else if (clength == 2)
X			cmask = IShort(control);
X		else
X			cmask = ILong(control);
X
X	/* now if it is zero, ignore and return */
X	if (cmask == 0)
X		return;
X
X	/* there are bits in the controlling bitmask, figure out which */
X	/* the ctype is a set type, so this code is similar to PrintSET */
X	fprintf(stdout, "%s%20s:\n", Leader, name);
X	ModifyIndentLevel(1);
X	for (p = TD[ctype].ValueList; p != NULL; p = p->Next)
X		{
X			if ((p->Value & cmask) != 0)
X				{
X					short   m = 4 - p->Length;
X					PrintField(values, m, p->Length, p->Type, p->Name);
X					values += 4;
X				}
X		}
X	ModifyIndentLevel(-1);
X}
X
X/* PolyText8 and PolyText16 take lists of characters with possible
X	font changes in them. */
X
XGlobal void
XPrintTextList8(buf, length, name)
X		unsigned char *buf;
X		short   length;
X		char   *name;
X{
X	short   n;
X
X	fprintf(stdout, "%s%20s:\n", Leader, name);
X	while (length > 1)
X		{
X			n = IByte(&buf[0]);
X			if (n != 255)
X				{
X					PrintField(buf, 1, 1, INT8, "delta");
X					PrintString8(&buf[2], n, "text item 8 string");
X					buf += n + 2;
X					length -= n + 2;
X				}
X			else
X				{
X					PrintField(buf, 1, 4, FONT, "font-shift-id");
X					buf += 4;
X					length -= 4;
X				}
X		}
X}
X
XGlobal void
XPrintTextList16(buf, length, name)
X		unsigned char *buf;
X		short   length;
X		char   *name;
X{
X	short   n;
X
X	fprintf(stdout, "%s%20s:\n", Leader, name);
X	while (length > 1)
X		{
X			n = IByte(&buf[0]);
X			if (n != 255)
X				{
X					PrintField(buf, 1, 1, INT8, "delta");
X					PrintString16(&buf[2], n, "text item 16 string");
X					buf += n + 2;
X					length -= n + 2;
X				}
X			else
X				{
X					PrintField(buf, 1, 4, FONT, "font-shift-id");
X					buf += 4;
X					length -= 4;
X				}
X		}
X}
X
XGlobal void
XDumpHexBuffer(buf, n)
X		unsigned char *buf;
X		long    n;
X{
X	short   i;
X	short   column;
X	char    h[6] /* one hex or octal character */ ;
X
X	column = 27 + SizeofLeader();
X	for (i = 0; i < n; i++)
X		{
X			/* get the hex representations */
X			sprintf(h, "%02x",(0xff & buf[i]));
X
X			/* check if these characters will fit on this line */
X			if ((column + strlen(h) + 1) > MAXline)
X				{
X					/* line will be too long -- print it */
X					fprintf(stdout, "\n");
X					column = 0;
X				}
X			fprintf(stdout, "%s ", h);
X			column += 3;
X		}
X}
SHAR_EOF
$TOUCH -am 0903162990 prtype.c &&
chmod 0664 prtype.c ||
echo "restore of prtype.c failed"
set `wc -c prtype.c`;Wc_c=$1
if test "$Wc_c" != "19125"; then
	echo original size 19125, current size $Wc_c
fi
fi
echo "End of part 3, continue with part 4"
exit 0

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.