/*
 * common.c - functions used by client.c, server.c, RPCdg.c & RPCst.c.
 *
 * CSc 645 Spring 1995  Jim Warhol
 *
 * common.c contains basic error and output handling functions called by
 * the client.c & server.c programs, and by the RPCdg.c & RPCst.c network
 * library routines. It must be compiled in with the main program by
 * including the name common.c on the cc command line.
 *
 * The print routines print only the first RPC_LIMIT messages beginning 
 * with "      RPC", after which they are ignored. This is to limit the
 * amount of low-level tracing output produced. Note that since multiple
 * processes are executing, each one will print RPC_LIMIT messages.
 *
 * NOTE: File I/O is performed to file descriptors stdoutx & stderrx 
 * instead of stdout/stderr because of NeXT system header file anomalies.
 *
 * common.c is used in conjunction with the common.h header file.
 *
 */

#include "common.h"
#include <strings.h>

/* compile-time constants */

#define stdoutx		1		/* standard output file ordinal */
#define stderrx		2		/* standard error file ordinal */
#define	PRINTBUFLEN	150		/* print buffer length */
#define RPC_LIMIT	25		/* print only first 75 RPC messages */

/* common library routines data definitions */

char printbuf[PRINTBUFLEN] = "X";	/* print buffer (X => uninitialized) */
int RPCcount = 0;			/* count of RPC messages printed */

/*
 * void error(char errmsg[]);
 *
 * error prints an error message and aborts the program. A new line 
 * character is appended to the end of the message.
 *
 */

void error(char errmsg[])
{
   errornn(errmsg, 0, 0);		/* simply call errornn() w/out %d %d */
   exit(-1);
}

/*
 * void errorn(char errmsg[], int n);
 *
 * errorn prints an error message containing an integer and aborts the
 * program. A new line character is appended to the end of the message.
 *
 */

void errorn(char errmsg[], int n)
{
   errornnn(errmsg, n, 0, 0);		/* simply call errornnn() w/out %d's */
}

/*
 * void errornn(char errmsg[], int n1, int n2);
 *
 * errornn prints an error message containing two integers and aborts the
 * program. A new line character is appended to the end of the message.
 *
 */

void errornn(char errmsg[], int n1, int n2)
{
   errornnn(errmsg, n1, n2, 0);		/* simply call errornnn() w/out %d's */
}

/*
 * void errornnn(char errmsg[], int n1, int n2, int n3);
 *
 * errornn prints an error message containing three integers and aborts 
 * the program. A new line character is appended to the end of the message.
 * The entire message is assembled in printbuf first and then printed
 * out atomically to ensure all output arrives at the terminal at the
 * same time.
 *
 */

void errornnn(char errmsg[], int n1, int n2, int n3)
{
   /* ensure enough room for message (less %d %d %d characters), and 
      expansion for integers (10 * 3) */

   if (strlen(errmsg)-2-2-2+10+10+10 > PRINTBUFLEN)
      error("errornnn: Message too long to fit in print buffer.");

   /* include text of error message and integers in print buffer, and print */

   sprintf(printbuf, errmsg, n1, n2, n3);
   printbuf[i = strlen(printbuf)] = '\n';
   write(stderrx, printbuf, i + 1);

   exit(-1);
}

/*
 * void print(char msg[]);
 *
 * print writes a message to standard output. Unlike the error functions, 
 * no new line character is added to the line.
 *
 */

void print(char msg[])
{
   /* skip if this is RPC message and RPC_LIMIT have already been printed */

   if (strncmp(msg, "      RPC", 9) == 0)	/* if RPC message */
      if (++RPCcount > RPC_LIMIT) return;

   if (strlen(msg) > PRINTBUFLEN)
      error("print: Message too long to fit in print buffer.");
   sprintf(printbuf, msg);
   write(stdoutx, printbuf, strlen(printbuf));
   return;
}

/*
 * void printn(char msg[], int n);
 *
 * printn writes a format string containing an integer to standard output.
 *
 */

void printn(char msg[], int n)
{
   printns(msg, n, "");		/* simply call printns() w/out %s */
   return;
}

/*
 * void printnn(char msg[], int n1, int n2);
 *
 * printnn writes a format string containing two integers to standard output.
 *
 */

void printnn(char msg[], int n1, int n2)
{
   if (strncmp(msg, "      RPC", 9) == 0)	/* if RPC message */
      if (++RPCcount > RPC_LIMIT) return;
   if (strlen(msg)-2-2+10 > PRINTBUFLEN)
      error("printnn: Message too long to fit in print buffer.");
   sprintf(printbuf, msg, n1, n2);
   write(stdoutx, printbuf, strlen(printbuf));
   return;
}

/*
 * void printnnn(char msg[], int n1, int n2, int n3);
 *
 * printnnn writes a format string containing three integers to standard output.
 *
 */

void printnnn(char msg[], int n1, int n2, int n3)
{
   if (strncmp(msg, "      RPC", 9) == 0)	/* if RPC message */
      if (++RPCcount > RPC_LIMIT) return;
   if (strlen(msg)-2-2-2+10 > PRINTBUFLEN)
      error("printnnn: Message too long to fit in print buffer.");
   sprintf(printbuf, msg, n1, n2, n3);
   write(stdoutx, printbuf, strlen(printbuf));
   return;
}

/*
 * void printns(char msg[], int n, char string[]);
 *
 * printns writes a format string containing an integer and a string to 
 * standard output.
 *
 */

void printns(char msg[], int n, char string[])
{
   if (strncmp(msg, "      RPC", 9) == 0)	/* if RPC message */
      if (++RPCcount > RPC_LIMIT) return;
   if (strlen(msg)-2-2+strlen(string)+10 > PRINTBUFLEN)
      error("printns: Message too long to fit in print buffer.");
   sprintf(printbuf, msg, n, string);
   write(stdoutx, printbuf, strlen(printbuf));
   return;
}

/*
 * void prints(char msg[], char string[]);
 *
 * prints writes a format string containing a string to standard output.
 *
 */

void prints(char msg[], char string[])
{
   printsn(msg, string, 0);		/* simply call printsn() w/out %d */
   return;
}

/*
 * void printsn(char msg[], char string[], int n);
 *
 * printsn writes a format string containing a string and an integer to 
 * standard output.
 *
 */

void printsn(char msg[], char string[], int n)
{
   if (strncmp(msg, "      RPC", 9) == 0)	/* if RPC message */
      if (++RPCcount > RPC_LIMIT) return;
   if (strlen(msg)-2-2+strlen(string)+10 > PRINTBUFLEN)
      error("printsn: Message too long to fit in print buffer.");
   sprintf(printbuf, msg, string, n);
   write(stdoutx, printbuf, strlen(printbuf));
   return;
}

/*
 * void printsnns(char msg[], char string1[], int n1, int2, char string2[]);
 *
 * printsnns writes a format string containing string1, integers n1 & n2, 
 * and string2 to standard output.
 *
 */

void printsnns(char msg[], char string1[], int n1, int n2, char string2[])
{
   if (strncmp(msg, "      RPC", 9) == 0)	/* if RPC message */
      if (++RPCcount > RPC_LIMIT) return;
   if (strlen(msg)-2-2-2-2+strlen(string1)+10+10+strlen(string2) > PRINTBUFLEN)
      error("printsnns: Message too long to fit in print buffer.");
   sprintf(printbuf, msg, string1, n1, n2, string2);
   write(stdoutx, printbuf, strlen(printbuf));
   return;
}

