/*
 * beauty.h  14 Oct 83
 *
 *	This file contains type definitions to make C code more
 * portable.  I'm afraid that the result is not beauty, however.
 * This is probably due to my FORTRAN background.
 *
 *	A basic assumption is that memory is adressable in units
 * called "bytes".  A "byte" must be at least 8 bits wide, but may be
 * wider.  All higher-order memory units are multiples of a byte
 * in width.  The following standard memory units must be present:
 *
 *	char	1 byte wide
 *	short	2 bytes wide
 *	long	4 bytes wide
 *
 *	The "char" data types present special problems.  The original
 * "C" language allowed char to be implemented as either a signed or
 * an unsigned type.  Although later revisions to the language added
 * an explicit unsigned char type, it is not yet possible to count
 * on universal compliance.
 */

/*
 *	The following definitions describe the characteristics of the
 * particular compiler and target system in use.
 */

#define NO_VOID			/* No void in this compiler. */
#define NO_UQUAL		/* No unsigned qualifier.  Unsigned
				 * is a separate type, same width as int. */
#define NO_SCHAR		/* No signed char. */
/* define NO_UCHAR		 No unsigned char. */
/* define NO_USHORT		 No unsigned short. */
#define NO_ULONG		/* No unsigned long. */
/* define NO_OSHORT		 No odd shorts, ie a short may not occur
				 * on an odd byte boundary. */
/* define NO_OLONG		 No odd longs, ie a long may not occur
				 * on an odd short boundary. */
#define EASY_CHAR		/* The char type doesn't cost extra. */
#define EASY_SHORT		/* The short type doesn't cost extra. */
#define MAXUCHAR 255		/* Max unsigned value of a char.  Must
				 * be one less than a power of two. */
#define LONG_PTR		/* A pointer is a long (4 bytes). */


/*
 *	Here are some derivatives that we will use later.
 */

#define MAXSCHAR (MAXUCHAR>>1)	/* Maximum signed value of a char. */
#define MINSCHAR (-(MAXSCHAR+1))
				/* Minimum signed value of a char. */


/*
 *	Here are definitions for types which must have exactly the
 * specified sign and length characteristics.  They are mapped into
 * the underlying "C" language base types.
 */

#ifndef NO_SCHAR
typedef char s_char;		/* A signed, one-byte integer. */
#endif
typedef short s_short;		/* A signed, two-byte integer. */
typedef long s_long;		/* A signed, four-byte integer. */

#ifndef NO_UQUAL		/* If "unsigned" is a qualifier: */
#ifndef NO_UCHAR
typedef unsigned char u_char;	/* An unsigned, one-byte integer. */
#endif
#ifndef NO_USHORT
typedef unsigned short u_short;	/* An unsigned, two-byte integer. */
#endif
#ifndef NO_ULONG
typedef unsigned long u_long;	/* An unsigned, four-byte integer. */
#endif

#else				/* If "unsigned" is a type: */
#ifndef NO_UCHAR
typedef char u_char;		/* An unsigned, one-byte integer. */
#endif
#ifndef NO_USHORT
typedef unsigned u_short;	/* An unsigned, two-byte integer. */
#endif
#ifndef NO_ULONG
typedef unsigned u_long;	/* An unsigned, four-byte integer. */
#endif
#endif


/*
 *	There is no particular guarantee that either signed chars or
 * unsigned chars will be present on a given implementation.  So, we
 * will create three classes of one-byte integers:  signed, unsigned,
 * and "positive".  Variables of all three classes can hold integers
 * in the range 0 to MAXSCHAR, and will return the same values
 * when read.  The "positive" integers are defined only over this
 * restricted range.
 */

typedef char p_char;		/* A restricted one-byte integer. */


/*
 *	The "signed" one-byte integers are defined on the range
 * MINSCHAR to MAXSCHAR.  The SCHAR function is used to read values
 * in this range.  Inline code fakes the conversion to "int", if
 * necessary.
 */

#ifdef NO_SCHAR
typedef char s_char;		/* We will fake a signed, one-byte int. */
#define SCHAR(x) (((x)>MAXSCHAR)?((x)|~MAXUCHAR):(x))
#else
#define SCHAR(x) (x)		/* Signed one-byte integers are natural. */
#endif


/*
 *	The "unsigned" one-byte integers are defined on the range 0
 * to MAXUCHAR.  The UCHAR function is used to read values in this
 * this range.  Inline code fakes the conversion to the computational
 * type "int", if necessary.
 */

#ifdef NO_UCHAR
typedef char u_char;		/* We will fake an unsigned, one-byte int. */
#define UCHAR(x) ((x)&MAXUCHAR)
#else
#define UCHAR(x) (x)		/* Unsigned one-byte integers are natural. */
#endif


/*
 *	Suppose that you want to declare a variable, but are not concerned
 * with its exact width as long as it is at least wide enough.  You would
 * probably like the most computationally efficient data type that will
 * hold the integer.  It might also be nice to do this portably.  Here
 * are some definitions to do this:
 */

#ifdef EASY_CHAR
typedef char e_char;		/* Holds 0 to 127 (avoiding sign problems). */
#else
typedef int e_char;		/* Holds 0 to 127 (avoiding sign problems). */
#endif

#ifdef EASY_SHORT
typedef short e_int;		/* Holds -32000 to 32000. */
#else
typedef int e_int;		/* Holds -32000 to 32000. */
#endif

typedef long e_long;		/* For completeness. */


/*
 *	The "void" type means that a function does not return a value,
 * or that a function's value is being ignored.  Since this data type
 * was added to the C language after "The C Programming Language" was
 * published, some compilers don't know about it.
 */

#ifdef NO_VOID
typedef int void;		/* Valueless value. */
#endif


/*
 *	Another deficiency of C is that it provides insufficient
 * "information hiding" primatives.  In particular, it is often
 * desirable to define a data type within a module or restricted set
 * of modules, and make only "handles" to instances of this type
 * available outside the module.  The handle is often expressed in
 * C using unsafe techniques, such as casting pointers to integers
 * and back again.  A better technique is to use a union of common
 * data and pointer types.  Unfortunately, some C compilers still
 * don't know that structs (and unions) may be passed to and returned
 * from functions.  Here is a final alternative:  declare a pointer to
 * the object with the finest grain, and cast and recast as needed.
 */

typedef u_char * PTR;		/* An arbitrary pointer, up to 4 bytes. */
#ifdef LONG_PTR
#define NULL (0L)		/* Indicates an empty pointer. */
#else
#define NULL (0)		/* Indicates an empty pointer. */
#endif

typedef PTR HANDLE;		/* A "handle" is a pointer or an int. */
