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.