/*
 * File: genlib.h
 * Version: MetroWerks Code Warrior
 * Last modified on Wed Apr  1 13:52:49 1998 by eroberts
 * -----------------------------------------------------
 * This file contains several definitions that form the
 * core of a general-purpose ANSI C library developed by Eric
 * Roberts.  The goal of this library is to provide a basic
 * set of tools and conventions that increase the readability
 * of C programs, particularly as they are used in a teaching
 * environment.
 *
 * The basic definitions provided by genlib.h are:
 *
 *    1.  Declarations for several new "primitive" types
 *        (most importantly bool and string) that are
 *        used throughout the other libraries and
 *        applications as fundamental types.
 *
 *    2.  A new set of functions for memory allocation.
 *
 *    3.  A function for error handling.
 *
 *    4.  A repeat statement for loops with interior exits.
 */

#ifndef _genlib_h
#define _genlib_h

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

/* Section 1 -- Define new "primitive" types */

/*
 * Type: bool
 * ----------
 * This type has two values, FALSE and TRUE, which are equal to 0
 * and 1, respectively.  Most of the advantage of defining this type
 * comes from readability because it allows the programmer to
 * provide documentation that a variable will take on only one of
 * these two values.
 */

#ifndef bool
#define bool int
#endif
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

/*
 * Type: string
 * ------------
 * The type string is identical to the type char *, which is
 * traditionally used in C programs.  The main point of defining a
 * new type is to improve program readability.   At the abstraction
 * levels at which the type string is used, it is usually not
 * important to take the string apart into its component characters.
 * Declaring it as a string emphasizes this atomicity.
 */

typedef char *string;

/*
 * Type: stream
 * ------------
 * Like string, the stream type is used to provide additional
 * readability and is defined to be equivalent to FILE *
 * (which is particularly confusing because it violates
 * standard case conventions).  This type is not used in
 * the text but is preserved in genlib.h, so it is possible
 * to teach all of CS1 without exposing any pointers.
 */

typedef FILE *stream;

/*
 * Constant: UNDEFINED
 * -------------------
 * Besides NULL, the only other constant of pointer type is
 * UNDEFINED, which is used in certain packages as a special
 * sentinel to indicate an undefined pointer value.  In many
 * such contexts, NULL is a legitimate data value and is
 * therefore inappropriate as a sentinel.
 */

#define UNDEFINED ((void *) undefined_object)

extern char undefined_object[];

/* Section 2 -- Memory allocation */

/*
 * General notes:
 * --------------
 * These functions provide a common interface for memory
 * allocation.  All functions in the library that allocate
 * memory do so using GetBlock and FreeBlock.  Even though
 * the ANSI standard defines malloc and free for the same
 * purpose, using GetBlock and FreeBlock provides greater
 * compatibility with non-ANSI implementations, automatic
 * out-of-memory error detection, and the possibility of
 * substituting a garbage-collecting allocator.
 */

/*
 * Function: GetBlock
 * Usage: ptr = (type) GetBlock(nbytes);
 * -------------------------------------
 * GetBlock allocates a block of memory of the given size.  If
 * no memory is available, GetBlock generates an error.
 */

void *GetBlock(size_t nbytes);

/*
 * Function: FreeBlock
 * Usage: FreeBlock(ptr);
 * ----------------------
 * FreeBlock frees the memory associated with ptr, which must
 * have been allocated using GetBlock, New, or NewArray.
 */

void FreeBlock(void *ptr);

/*
 * Macro: New
 * Usage: p = New(pointer-type);
 * -----------------------------
 * The New pseudofunction allocates enough space to hold an
 * object of the type to which pointer-type points and returns
 * a pointer to the newly allocated pointer.  Note that
 * "New" is different from the "new" operator used in C++;
 * the former takes a pointer type and the latter takes the
 * target type.
 */

#define New(type) ((type) GetBlock(sizeof *((type) NULL)))

/*
 * Macro: NewArray
 * Usage: p = NewArray(n, element-type);
 * -------------------------------------
 * NewArray allocates enough space to hold an array of n
 * values of the specified element type.
 */

#define NewArray(n, type) ((type *) GetBlock((n) * sizeof (type)))

/* Section 3 -- Basic error handling */

/*
 * Function: Error
 * Usage: Error(msg, ...)
 * ----------------------
 * Error generates an error string, expanding % constructions
 * appearing in the error message string just as printf does.
 * If an error handler exception has been introduced (see the
 * "exception.h" facility), the ErrorException exception is
 * raised with the expanded error string as argument.  If
 * there is no ErrorException defined, the program exits
 * with a status code indicating failure (as given by the
 * constant ErrorExitStatus).  The length of the error
 * message string following expansion must not exceed
 * MaxErrorMessage, and it is the client's responsibility
 * to ensure this.
 */

void Error(string msg, ...);

/* Section 4 -- The repeat pseudo-statement */

/*
 * Statement form: repeat { ... }
 * ------------------------------
 * Some instructors who have taught CS1 using this library
 * have found that using
 *
 *     while (TRUE)
 *
 * to initiate a loop with an interior exit is confusing to
 * students, particularly when it comes at the beginning of
 * the course.  This macro defines "repeat" as an infinite
 * loop construct for instructors who find it easier to
 * explain, although it is not used in the text.   Similar
 * macro definitions are common in industry.
 */

#define repeat for (;;)

/* Section 5 -- Metrowerks specific definitions */

/*
 * Function macro: main
 * --------------------
 * The only purpose of this macro definition is to make it possible
 * for code written using the MetroWerks compiler to match that
 * in the textbook without generating warnings about failure to
 * return an integer.
 */

#define main() extern void Main(void); int main() { Main(); return 0; } void Main(void)

#endif
