[NeoStats-Devel] [Commits] r2810 - trunk/include

[email protected] Mon, 12 Sep 2005 23:57:42 +1000
Newsgroups gmane.comp.neostats.devel
Message-ID <[email protected]>
Author: Fish
Date: Mon Sep 12 21:57:35 2005
New Revision: 2810

Added:
   trunk/include/MiniMessage.h   (contents, props changed)
   trunk/include/MiniMessageGateway.h   (contents, props changed)
   trunk/include/MuscleSupport.h   (contents, props changed)
Log:
Commit the MiniMessage files


Added: trunk/include/MiniMessage.h
==============================================================================
--- (empty file)
+++ trunk/include/MiniMessage.h	Mon Sep 12 21:57:35 2005
@@ -0,0 +1,602 @@
+/* NeoStats - IRC Statistical Services
+** Copyright (c) 1999-2005 Adam Rutter, Justin Hammond, Mark Hetherington
+** http://www.neostats.net/
+**
+**  Portions Copyright (c) 2000 - 2001 ^Enigma^
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+**  USA
+**
+** NeoStats CVS Identification
+** $Id$
+*/
+
+
+#ifndef MiniMessage_h
+#define MiniMessage_h
+
+#include "MuscleSupport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* My own little boolean type, since C doesn't come with one built in. */
+typedef char MBool;
+enum {MFalse = 0, MTrue};  /* and boolean values to go in it */
+
+/* This file contains a C API for a "minimalist" implementation of the MUSCLE  */
+/* Message dictionary object.  This implementation sacrifices a certain amount */
+/* of flexibility and convenience in exchange for a very lightweight           */
+/* and efficient implementation.                                               */
+
+/** Definition of our Point class -- two floats */
+struct _MPoint {
+   float x;
+   float y;
+};
+typedef struct _MPoint MPoint;
+
+/** Definition of our Rect class -- four floats */
+struct _MRect {
+   float left;
+   float top;
+   float right;
+   float bottom;
+};
+typedef struct _MRect MRect;
+
+/** Definition of our opaque handle to a MMessage object.  Your
+  * code doesn't know what a (MMessage *) points to, and it doesn't care,
+  * because all operations on it should happen via calls to the functions
+  * that are defined below.
+  */
+struct _MMessage;
+typedef struct _MMessage MMessage;
+
+/** This object is used in field name iterations */
+struct _MMessageIterator {
+   const MMessage * message;
+   void * iterState; 
+   uint32 typeCode;
+};
+typedef struct _MMessageIterator MMessageIterator;
+
+/** Definition of our byte-array class, including size value */
+struct _MByteBuffer {
+   uint32 numBytes;
+   uint8 bytes;  /* Note that this is only the first byte; there are usually more after this one */
+};
+typedef struct _MByteBuffer MByteBuffer;
+
+/** Allocates and initializes a new MByteBuffer with the specified number of bytes, and returns a pointer to it. 
+  * @param numBytes How many bytes to allocate in this buffer.
+  * @param clearBytes If MTrue, all the data bytes in the returned MByteBuffer will be zero.
+  *                   If MFalse, the bytes' values will be undefined (which is a bit more efficient)
+  * @returns a newly allocated MByteBuffer with the specified number of bytes, or NULL on failure.  
+  *          If non-NULL, it becomes the the responsibility of the calling code to call FreeMByteBuffer() 
+  *          on the MByteBuffer when it is done using it. 
+  */
+MByteBuffer * MBAllocByteBuffer(uint32 numBytes, MBool clearBytes);
+
+/** Allocates and initializes a new MByteBuffer to contain a copy of the specified NUL-terminated string.
+  * @param sourceString The string to copy into the newly allocated byte buffer.
+  * @returns A newly allocated MByteBuffer containing a copy of the specified string, or NULL on failure.
+  *          Note that the returned MByteBuffer's string will be NUL-terminated too.
+  */
+MByteBuffer * MBStrdupByteBuffer(const char * sourceString);
+
+/** Attempts to create and return a cloned copy of (cloneMe).
+  * @param cloneMe The MByteBuffer to create a copy of.  
+  * @returns The newly allocated MByteBuffer, or NULL on failure.
+  */
+MByteBuffer * MBCloneByteBuffer(const MByteBuffer * cloneMe);
+
+/** Returns MTrue iff the two byte buffers are equal (i.e. both hold the same byte sequence)
+  * @param buf1 The first byte buffer to compare.
+  * @param buf2 The first byte buffer to compare.
+  * @returns True if buf1 has the same byte sequence as buf2, otherwise MFalse.
+  */
+MBool MBAreByteBuffersEqual(const MByteBuffer * buf1, const MByteBuffer * buf2);
+
+/** Frees a previously created MByteBuffer and all the data that it holds.
+  * @param msg The MByteBuffer to free.  If NULL, no action will be taken.
+  */
+void MBFreeByteBuffer(MByteBuffer * msg);
+
+/** Allocates and initializes a new MMessage with the specified what code, and returns a pointer to it. 
+  * @param what Initial 'what' code to give to the MMessage.
+  * @returns a newly allocated MMessage, or NULL on failure.  If non-NULL, it becomes the
+  *          the responsibility of the calling code to call MMFreeMessage() on the MMessage
+  *          when it is done using it. 
+  */
+MMessage * MMAllocMessage(uint32 what);
+
+/** Attempts to create and return a cloned copy of (cloneMe).
+  * @param cloneMe The MMessage to create a copy of.  
+  * @returns The newly allocated MMessage, or NULL on failure.
+  */
+MMessage * MMCloneMessage(const MMessage * cloneMe);
+
+/** Frees a previously created MMessage and all the data that it holds.
+  * @param msg The MMessage to free.  If NULL, no action will be taken.
+  */
+void MMFreeMessage(MMessage * msg);
+
+/** Returns the 'what' code associated with the specified MMessage. 
+  * @param msg The MMessage to retrieve the 'what' code of.'
+  * @returns The MMessage's what code.
+  */
+uint32 MMGetWhat(const MMessage * msg);
+
+/** Sets the 'what' code associated with the specified MMessage. 
+  * @param msg The MMessage to set the 'what' code of'.
+  * @param newWhat The new 'what' code to install.  (Typically a B_*_TYPE value)
+  */
+void MMSetWhat(MMessage * msg, uint32 newWhat);
+
+/** Removes and frees all of the supplied MMessage's field data.  The MMessage itself
+  * is not destroyed, however (use MMFreeMessage() to do that)
+  * @param msg The MMessage object to remove all data fields from.
+  */
+void MMClearMessage(MMessage * msg);
+
+/** Attempts to remove and free the specified field from the given MMessage.
+  * @param msg the MMessage object to remove the field from
+  * @param fieldName Name of the field to remove and free. 
+  * @returns B_NO_ERROR if the field was found and removed, or B_ERROR if it wasn't found.
+  */
+status_t MMRemoveField(MMessage * msg, const char * fieldName);
+
+/** Attempts to create and install a string field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if a string field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all NULL string values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) MByteBuffer pointers, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  *          The MByteBuffer pointers in the array, when non-NULL, are also considered to belong to the
+  *          MMessage, and will have MBFreeByteBuffer() called on them when the field is destroyed.  
+  *          NOTE: When setting a value in the array, be sure to allocate its memory using MBAllocByteBuffer()
+  *                or MBStrdupByteBuffer(), and be sure to call MBFreeByteBuffer() on the old value before
+  *                you replace it.
+  */
+MByteBuffer ** MMPutStringField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install a boolean field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if a boolean field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all data values set to MFalse.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) booleans, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+MBool * MMPutBoolField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install an int8 field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if an int8 field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all zero data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) int8s, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+int8 * MMPutInt8Field(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install an int16 field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if an int16 field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all zero data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) int16s, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+int16 * MMPutInt16Field(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install an int32 field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if an int32 field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all zero data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) int32s, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+int32 * MMPutInt32Field(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install an int64 field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if an int64 field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all zero data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) int64s, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+int64 * MMPutInt64Field(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install a float field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if a float field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all zero data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) floats, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+float * MMPutFloatField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install a double field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if a double field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all zero data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) doubles, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+double * MMPutDoubleField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install a Message field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if a Message field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all NULL data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) Messages, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  *          NOTE:  Any MMessages that this array points to are considered to be owned by the MMessage
+  *                 as well, for as long as they are pointed to by the array.  So when setting the array
+  *                 values, be sure to follow pointer semantics, such that any new values are allocated
+  *                 off the heap, and be sure to call MMFreeMessage() on any values you replace.
+  */
+MMessage ** MMPutMessageField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install a pointer field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if a pointer field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all NULL data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) pointers, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+void ** MMPutPointerField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install a point field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if a point field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all zero data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) points, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+MPoint * MMPutPointField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install a rect field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if a rect field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all zero data values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) rects, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  */
+MRect * MMPutRectField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems);
+
+/** Attempts to create and install an untyped data field with the specified field name into the MMessage.
+  * On success, any previously installed field with the same name will be replaced and freed.
+  * @param msg The MMessage to install the new field into.
+  * @param retainOldData This flag is relevant only if a data field with the same name already exists.
+  *                      If MTrue, as many of the old field's data values as possible will be transferred
+  *                      to the new field.  Otherwise, all the old field's data will be destroyed and the
+  *                      new field will be created with all NULL string values.
+  * @param fieldName Field name of the new field.
+  * @param numItems Number of items that the new field should contain room for.
+  * @returns A pointer to an array of (numItems) MByteBuffer pointers, or NULL if there was an error.
+  *          The returned array belongs to the MMessage, and will be freed by it at the proper time.
+  *          The MByteBuffer pointers in the array, when non-NULL, are also considered to belong to the
+  *          MMessage, and will have MBFreeByteBuffer() called on them when the field is destroyed.  
+  *          NOTE: When setting a value in the array, be sure to allocate its memory using MBAllocByteBuffer()
+  *                or MBStrdupByteBuffer(), and be sure to call MBFreeByteBuffer() on the old value before
+  *                you replace it.
+  */
+MByteBuffer ** MMPutDataField(MMessage * msg, MBool retainOldData, uint32 typeCode, const char * fieldName, uint32 numItems);
+
+/** Returns the number of bytes it would take to hold a flattened representation of (msg). 
+  * @param msg MMessage to scan to determine its flattened size.
+  * @returns Number of bytes the flattened representation would require.
+  */
+uint32 MMGetFlattenedSize(const MMessage * msg);
+
+/** Flattens the supplied MMessage into a platform-neutral byte buffer that can be sent out over the
+  * network or saved to disk and later reassembled back into an equivalent MMessage object by calling
+  * MMUnflattenMessage().
+  * @param msg MMessage to produce the byte buffer from.
+  * @param outBuf Pointer to the output array to write into.  There must be at least
+  *               MMGetFlattenedSize(msg) bytes of storage available at this location,
+  *               or memory corruption will result.  The output into this buffer will be in
+  *               with the standard MUSCLE flattened byte buffer format.
+  */
+void MMFlattenMessage(const MMessage * msg, void * outBuf);
+
+/** Unflattens the supplied byte buffer into the supplied MMessage object.
+  * @param msg MMessage object to set the state of, based on the contents of the flattened byte buffer.
+  * @param inBuf Buffer containing the flattened MMessage bytes, as previously created by 
+  *              MMFlattenMessage() (or some other code that writes the flattened MUSCLE Message format).
+  * @param bufSizeBytes How many valid bytes of data are available at (inBuf).
+  * @returns B_NO_ERROR if the restoration was a success, or B_ERROR otherwise (in which case (msg) will
+  *                     likely be left in some valid but only partially restored state)
+  */
+status_t MMUnflattenMessage(MMessage * msg, const void * inBuf, uint32 bufSizeBytes);
+
+/** Moves the specified field from one MMessage to another.
+  * @param sourceMessage The MMessage where the field currently resides.
+  * @param fieldName Name of the field to move.
+  * @param destMsg The MMessage to move the field to.  If a field with this name already exists
+  *                inside (destMsg), it will be replaced and freed.  If (destMsg) is NULL, the
+  *                field will be removed from the source Message and freed.
+  * @returns B_NO_ERROR on success, or B_ERROR on failure.  
+  */
+status_t MMMoveField(MMessage * sourceMsg, const char * fieldName, MMessage * destMsg);
+
+/** Copies the specified field from one MMessage to another.
+  * @param sourceMessage The MMessage where the field currently resides.
+  * @param fieldName Name of the field to copy.
+  * @param destMsg The MMessage to copy the field to.  If a field with this name already exists
+  *                inside (destMsg), it will be replaced and freed.  If (destMsg) is NULL, this
+  *                call will have no effect.
+  * @returns B_NO_ERROR on success, or B_ERROR on failure.  
+  */
+status_t MMCopyField(const MMessage * sourceMsg, const char * fieldName, MMessage * destMsg);
+
+/** Change the name of a field within its Message.
+  * @param sourceMessage The MMessage where the field currently resides.
+  * @param oldFieldName Current name of the field.
+  * @param newFieldName Desired new name of the field.  If a field with this name already exists
+  *                inside (sourceMsg), it will be replaced and freed.
+  * @returns B_NO_ERROR on success, or B_ERROR on failure.  
+  */
+status_t MMRenameField(MMessage * sourceMsg, const char * oldFieldName, const char * newFieldName);
+
+/** Retrieves the string field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of MByteBuffers that represents the strings on success, or NULL on failure.
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+MByteBuffer ** MMGetStringField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the boolean field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of MBool on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+MBool * MMGetBoolField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the int8 field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of int8s on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+int8 * MMGetInt8Field(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the int16 field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of int16s on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+int16 * MMGetInt16Field(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the int32 field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of int32s on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+int32 * MMGetInt32Field(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the int64 field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of int64 on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+int64 * MMGetInt64Field(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the float field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of floats on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+float * MMGetFloatField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the double field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of doubles on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+double * MMGetDoubleField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the Message field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of Messages on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+MMessage ** MMGetMessageField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the pointer field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of pointers on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+void ** MMGetPointerField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the point field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of points on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+MPoint * MMGetPointField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the rect field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of rects on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+MRect * MMGetRectField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems);
+
+/** Retrieves the data field with the given name.
+  * @param msg The MMessage to look for the field in.
+  * @param typeCode The typecode of the field to look for, or B_ANY_TYPE if you aren't particular about type.
+  * @param fieldName Name of the field to look for.
+  * @param optRetNumItems If non-NULL, the number of items in the field will be written into the uint32 this points to.
+  * @returns A pointer to the array of data items on success, or NULL on failure (field not found).
+  *          Note that the returned array remains under the ownership of the MMessage object.
+  */
+MByteBuffer ** MMGetDataField(const MMessage * msg, uint32 typeCode, const char * fieldName, uint32 * optRetNumItems);
+
+/** Returns information about the type and size of the specified field.
+  * @param msg The MMessage to look for the field in.
+  * @param fieldName The name of the field to look for.
+  * @param typeCode The typecode of the field to look for, or B_ANY_TYPE if you aren't particular about type.
+  * @param optRetNumItems If non-NULL, on success the uint32 this points to will have the number of items in the field written into it.
+  * @param optRetTypeCode If non-NULL, on success the uint32 this points to will have the type code of the field written into it.
+  * @returns B_NO_ERROR if the field was found, or B_ERROR if no field with the specified name and type were present.
+  */
+status_t MMGetFieldInfo(const MMessage * msg, const char * fieldName, uint32 typeCode, uint32 * optRetNumItems, uint32 * optRetTypeCode);
+
+/** Returns MTrue iff the two MMessage objects are exactly equivalent.  (Note that field ordering is not considered)
+  * @param msg1 First MMessage to compare.  Must not be NULL.
+  * @param msg2 Second MMessage to compare.  Must not be NULL.
+  * @returns MTrue If the two MMessage objects are equal; MFalse otherwise.
+  */
+MBool MMAreMessagesEqual(const MMessage * msg1, const MMessage * msg2);
+
+/** Prints the contents of this MMessage to stdout.  Useful for debugging.
+  * @param msg The MMessage to print the contents of to stdout.
+  */
+void MMPrintToStream(const MMessage * msg);
+
+/** Returns an iterator object that you can use to iterator over the field names of this MMessage.
+  * @param msg The MMessage object over whose field names you wish to iterate.
+  * @param typeCode The type of field you are interested in, or B_ANY_TYPE if you aren't particular.
+  * @returns the iterator object, suitable, for passing in to the MMGetNextFieldName() function.
+  * @note It is an error to remove or replace fields in a MMessage object while iterating over it.
+  */
+MMessageIterator MMGetFieldNameIterator(const MMessage * msg, uint32 typeCode);
+
+/** Returns the next field name in the field name iteration, or NULL if there are no more field names.
+  * @param iteratorPtr This should point to the iterator object that was returned by a MMGetFieldNameIterator() call.
+  * @param optRetTypeCode If non-NULL, the uint32 this points to will have the next field's type code written into it.
+  * @returns The next field name, or NULL if the iteration is complete.
+  */
+const char * MMGetNextFieldName(MMessageIterator * iteratorPtr, uint32 * optRetTypeCode);
+
+#ifdef MUSCLE_ENABLE_MEMORY_TRACKING
+
+/** A wrapper for malloc() that allows us to track the number of bytes currently allocated.  
+  * Good for catching memory leaks.  Only enabled if MUSCLE_ENABLE_MEMORY_TRACKING is defined; otherwise #defined to malloc().
+  */
+void * MMalloc(uint32 numBytes);
+
+/** A wrapper for free() that allows us to track the number of bytes currently allocated.
+  * Good for catching memory leaks.  Only enabled if MUSCLE_ENABLE_MEMORY_TRACKING is defined; otherwise #defined to free().
+  */
+void * MFree(void * ptr);
+
+/** A wrapper for realloc() that allows us to track the number of bytes currently allocated.
+  * Good for catching memory leaks.  Only enabled if MUSCLE_ENABLE_MEMORY_TRACKING is defined; otherwise #defined to realloc().
+  */
+void * MRealloc(void * oldBuf, uint32 newSize);
+
+#else
+# define MMalloc  malloc
+# define MRealloc realloc
+# define MFree    free
+#endif
+
+/** Returns the current number of allocated bytes. 
+  * Good for catching memory leaks.  Only enabled if MUSCLE_ENABLE_MEMORY_TRACKING is defined; otherwise always returns zero.
+  */
+uint32 MGetNumBytesAllocated();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif

Added: trunk/include/MiniMessageGateway.h
==============================================================================
--- (empty file)
+++ trunk/include/MiniMessageGateway.h	Mon Sep 12 21:57:35 2005
@@ -0,0 +1,113 @@
+/* NeoStats - IRC Statistical Services
+** Copyright (c) 1999-2005 Adam Rutter, Justin Hammond, Mark Hetherington
+** http://www.neostats.net/
+**
+**  Portions Copyright (c) 2000 - 2001 ^Enigma^
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+**  USA
+**
+** NeoStats CVS Identification
+** $Id$
+*/
+
+#ifndef MiniMessageGateway_h
+#define MiniMessageGateway_h
+
+#include "MiniMessage.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Definition of our opaque handle to a MMessageGateway object.  Your
+  * code doesn't know what a (MMessageGateway *) points to, and it doesn't care,
+  * because all operations on it should happen via calls to the functions
+  * that are defined below.
+  */
+struct _MMessageGateway;
+typedef struct _MMessageGateway MMessageGateway;
+
+/** Typedef for a callback function that knows how to read data from a buffer and send it
+  * out to (a file, the network, a serial line, wherever).
+  * @param buf The buffer to read bytes from.
+  * @param numBytes The number of bytes available for reading at (buf)
+  * @param arg This is a user-specified value; it will be the same as the value passed in to MMDoOutput().
+  * @returns The number of bytes actually read from (buf), or a negative value if there was a critical error (e.g. disconnected socket).
+  */
+typedef int32 (*MGSendFunc)(const uint8 * buf, uint32 numBytes, void * arg);
+
+/** Typedef for a callback function that knows how to read data from 
+  * (a file, the network, a serial line, wherever) and write it into a supplied buffer.
+  * @param buf The buffer to write bytes to.
+  * @param numBytes The number of bytes available for writing at (buf)
+  * @param arg This is a user-specified value; it will be the same as the value passed in to MMDoInput().
+  * @returns The number of bytes actually written into (buf), or a negative value if there was a critical error (e.g. disconnected socket).
+  */
+typedef int32 (*MGReceiveFunc)(uint8 * buf, uint32 numBytes, void * arg);
+
+/** Allocates and initializes a new MMessageGateway.
+  * @returns a newly allocated MMessageGateway, or NULL on failure.  If non-NULL, it becomes the
+  *          the responsibility of the calling code to call MMFreeMessageGateway() on the 
+  *          MMessageGateway when it is done using it. 
+  */
+MMessageGateway * MGAllocMessageGateway();
+
+/** Frees a previously created MMessageGateway and all the data that it holds.
+  * @param msg The MMessageGateway to free.  If NULL, no action will be taken.
+  */
+void MGFreeMessageGateway(MMessageGateway * gw);
+
+/** Flattens the given MMessage into bytes and adds the result to our queue of outgoing data.
+  * @param gw The Gateway to add the message data to.
+  * @param msg The MMessage object to flatten.  Note that the gateway DOES NOT assume ownership of this MMessage!
+  *            You are still responsible for freeing it, and may do so immediately on return of this function, if you wish.
+  * @returns B_NO_ERROR on success, or B_ERROR on error (out of memory?)
+  */
+status_t MGAddOutgoingMessage(MMessageGateway * gw, const MMessage * msg);
+
+/** Returns MTrue iff the given gateway has any output bytes queued up, that it wants to send.
+  * @param gw The Gateway to query.
+  * @returns MTrue if there are bytes queued up to send, or MFalse otherwise.
+  */
+MBool MGHasBytesToOutput(const MMessageGateway * gw);
+
+/** Writes out as many queued bytes as possible (up to maxBytes).
+  * @param gw The Gateway that should do the outputting.
+  * @param maxBytes The maximum number of bytes that should be sent by this function call.  Pass in ~0 to write without limit.
+  * @param sendFunc The function that the gateway way will call to actually do the write operation.
+  * @param arg The argument to pass to the write function.
+  * @returns The number of bytes written, or a negative number if there was an error.
+  */
+int32 MGDoOutput(MMessageGateway * gw, uint32 maxBytes, MGSendFunc sendFunc, void * arg);
+
+/** Reads in as many queued bytes as possible (up to maxBytes, or until a full MMessage is read).
+  * @param gw The Gateway that should do the inputting.
+  * @param maxBytes The maximum number of bytes that should be read by this function call.  Pass in ~0 to read without limit.
+  * @param recvFunc The function that the gateway way will call to actually do the read operation.
+  * @param arg The argument to pass to the read function.
+  * @param optRetMsg If non-NULL, the pointer this argument points to will be set to a returned MMessage object
+  *                  if there is one ready, or NULL otherwise.  NOTE:  If the pointer is set non-NULL, it becomes
+  *                  the calling code's responsibility to call MMFreeMessage() on the pointer when you are done with it!
+  *                  Failure to do so will result in a memory leak.
+  * @returns The number of bytes read, or a negative number if there was an error.
+  */
+int32 MGDoInput(MMessageGateway * gw, uint32 maxBytes, MGReceiveFunc recvFunc, void * arg, MMessage ** optRetMsg);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif

Added: trunk/include/MuscleSupport.h
==============================================================================
--- (empty file)
+++ trunk/include/MuscleSupport.h	Mon Sep 12 21:57:35 2005
@@ -0,0 +1,757 @@
+/* NeoStats - IRC Statistical Services
+** Copyright (c) 1999-2005 Adam Rutter, Justin Hammond, Mark Hetherington
+** http://www.neostats.net/
+**
+**  Portions Copyright (c) 2000 - 2001 ^Enigma^
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+**  USA
+**
+** NeoStats CVS Identification
+** $Id$
+*/
+
+/* This file is Copyright 2005 Level Control Systems.  See the included LICENSE.txt file for details. */
+
+/******************************************************************************
+/
+/     File:     MuscleSupport.h
+/
+/     Description:  Standard types, macros, etc, for MUSCLE.
+/                   Many of them are suspiciously BeOS-like.  ;^)
+/
+*******************************************************************************/
+
+#ifndef MuscleSupport_h
+#define MuscleSupport_h
+
+#define MUSCLE_VERSION_STRING "3.01"
+
+/* Define this if the default FD_SETSIZE is too small for you (i.e. under Windows it's only 64) */
+#if defined(MUSCLE_FD_SETSIZE)
+# if defined(FD_SETSIZE)
+#  error "MuscleSupport.h:  Can't redefine FD_SETSIZE, someone else has already defined it!  You need to include MuscleSupport.h before including any other header files that define FD_SETSIZE."
+# else
+#  define FD_SETSIZE MUSCLE_FD_SETSIZE
+# endif
+#endif
+
+/* If we are in an environment where known assembly is available, make a note of that fact */
+#if defined(__GNUC__)
+# if (defined(__PPC__) || defined(__APPLE__))
+#  define MUSCLE_USE_POWERPC_INLINE_ASSEMBLY 1
+# elif defined(__i386__)
+#  define MUSCLE_USE_X86_INLINE_ASSEMBLY 1
+# endif
+#endif
+
+#if defined(_MSC_VER) && defined(_X86_)
+# define MUSCLE_USE_X86_INLINE_ASSEMBLY 1
+#endif
+
+#ifndef __cplusplus
+# define MUSCLE_AVOID_NAMESPACES
+# define NEW_H_NOT_AVAILABLE
+#endif
+
+/* Since certain antique compilers don't support namespaces, we
+ * do all namespace-related declarations via macros which can
+ * be no-op'd out by declaring -DMUSCLE_AVOID_NAMESPACES in the Makefile.
+ */
+#ifdef MUSCLE_AVOID_NAMESPACES
+# define DECLARE_NAMESPACE(x)
+# define BEGIN_NAMESPACE(x)
+# define END_NAMESPACE(x)
+# define USING_NAMESPACE(x)
+#else
+# define DECLARE_NAMESPACE(x) namespace x {};
+# define BEGIN_NAMESPACE(x) namespace x {
+# define END_NAMESPACE(x) };
+# define USING_NAMESPACE(x) using namespace x;
+#endif
+
+/* Just declare the muscle namespace as existing.
+ * If we ever decide to make the muscle namespace a superset
+ * of another namespace, we would add a 'using namespace' line here.
+ */
+DECLARE_NAMESPACE(muscle);
+
+/* these CPUs can't handle non-aligned word reads, so we'll accomodate them by using memcpy() instead. */
+#if defined(MIPS) || defined(mc68000) || defined(sparc) || defined(__sparc) || defined(m68k) || defined(__68k__) || defined(__sparc__)
+# define MUSCLE_CPU_REQUIRES_DATA_ALIGNMENT
+#endif
+
+/* Borland C++ builder also runs under Win32, but it doesn't set this flag So we'd better set it ourselves. */
+#ifdef __BORLANDC__
+# ifndef WIN32
+#  define WIN32 1
+# endif
+#endif
+
+/* VC++ can't handle this stuff, it's too lame */
+#ifdef WIN32
+# define UNISTD_H_NOT_AVAILABLE
+# define NEW_H_NOT_AVAILABLE
+#endif
+
+#ifndef UNISTD_H_NOT_AVAILABLE
+# include <unistd.h>
+#endif
+
+#ifndef NEW_H_NOT_AVAILABLE
+# include <new>
+# ifndef MUSCLE_AVOID_NAMESPACES
+#  ifndef __MWERKS__
+using std::bad_alloc;
+using std::nothrow_t;
+using std::nothrow;
+using std::new_handler;
+using std::set_new_handler;
+#  endif
+# endif
+#else
+# define MUSCLE_AVOID_NEWNOTHROW
+#endif
+
+#ifndef newnothrow
+# ifdef MUSCLE_AVOID_NEWNOTHROW
+#  define newnothrow new
+# else
+#  define newnothrow new (nothrow)
+# endif
+#endif
+
+/* Unfortunately, the 64-bit printf() format specifier is different for different compilers :^P */
+#if defined(__MWERKS__) || defined(WIN32) || defined(__BORLANDC__) || defined(__BEOS__)
+# if (_MSC_VER == 1200)
+#  define  INT64_FORMAT_SPEC "%I64i"
+#  define UINT64_FORMAT_SPEC "%I64u"
+# else
+#  define  INT64_FORMAT_SPEC "%Li"
+#  define UINT64_FORMAT_SPEC "%Lu"
+# endif
+#else
+#  define  INT64_FORMAT_SPEC "%lli"
+#  define UINT64_FORMAT_SPEC "%llu"
+#endif
+
+#ifdef __BEOS__
+# include <kernel/debugger.h>
+# define MCRASH_IMPL debugger("muscle assertion failure")
+#elif defined(WIN32)
+# if defined(UNICODE)
+#  define MCRASH_IMPL FatalAppExit(0, L"muscle assertion failure")
+# else
+#  define MCRASH_IMPL FatalAppExit(0, "muscle assertion failure")
+# endif
+#else
+# define MCRASH_IMPL *((uint32*)NULL) = 0x666
+#endif
+
+#ifdef MUSCLE_AVOID_ASSERTIONS
+# define MASSERT(x,msg)
+#else
+# define MASSERT(x,msg) {if(!(x)) MCRASH(msg)}
+#endif
+
+#ifdef MUSCLE_AVOID_NAMESPACES
+# define MCRASH(msg) {LogTime(MUSCLE_LOG_CRITICALERROR, "ASSERTION FAILED: (%s:%i) %s\n", __FILE__,__LINE__,msg); LogStackTrace(MUSCLE_LOG_CRITICALERROR); MCRASH_IMPL;}
+# define WARN_OUT_OF_MEMORY LogTime(MUSCLE_LOG_CRITICALERROR, "ERROR--OUT OF MEMORY!  (%s:%i)\n",__FILE__,__LINE__)
+# define MCHECKPOINT LogTime(MUSCLE_LOG_WARNING, "Reached checkpoint at %s:%i\n", __FILE__, __LINE__)
+#else
+# define MCRASH(msg) {muscle::LogTime(muscle::MUSCLE_LOG_CRITICALERROR, "ASSERTION FAILED: (%s:%i) %s\n", __FILE__,__LINE__,msg); muscle::LogStackTrace(MUSCLE_LOG_CRITICALERROR); MCRASH_IMPL;}
+# define WARN_OUT_OF_MEMORY muscle::LogTime(muscle::MUSCLE_LOG_CRITICALERROR, "ERROR--OUT OF MEMORY!  (%s:%i)\n",__FILE__,__LINE__)
+# define MCHECKPOINT muscle::LogTime(muscle::MUSCLE_LOG_WARNING, "Reached checkpoint at %s:%i\n", __FILE__, __LINE__)
+#endif
+
+#define UNLESS(x) if(!(x))
+#define ARRAYITEMS(x) (sizeof(x)/sizeof(x[0]))  /* returns # of items in array */
+
+typedef void * muscleVoidPointer;  /* it's a bit easier, syntax-wise, to use this type than (void *) directly in some cases. */
+
+#ifdef __BEOS__
+# include <support/Errors.h>
+# include <support/ByteOrder.h>  /* might as well use the real thing (and avoid complaints about duplication) */
+# include <support/SupportDefs.h>
+# include <support/TypeConstants.h>
+# ifdef BONE
+#  define closesocket close
+# else
+#  define BEOS_OLD_NETSERVER
+# endif
+#else
+# define B_ERROR    -1
+# define B_NO_ERROR 0
+# define B_OK       B_NO_ERROR
+# ifndef WIN32
+#  define closesocket close
+# endif
+# ifdef __ATHEOS__
+#  include </ainc/atheos/types.h>
+# else
+#  ifndef MUSCLE_TYPES_PREDEFINED  /* certain (ahem) projects already set these themselves... */
+#   define true                     1
+#   define false                    0
+    typedef signed char             int8;
+    typedef unsigned char           uint8;
+    typedef short                   int16;
+    typedef unsigned short          uint16;
+#   if defined(__osf__)     /* some 64bit systems will have long=64-bit, int=32-bit */
+     typedef int                    int32;
+     typedef unsigned int           uint32;
+#   elif defined(__amd64__) /* some 64bit systems will have long=64-bit, int=32-bit */
+     typedef int                    int32;
+     typedef unsigned int           uint32;
+#   else
+     typedef long                   int32;
+     typedef unsigned long          uint32;
+#   endif
+#   if defined(WIN32) && !defined(__GNUWIN32__)
+     typedef __int64                int64;
+     typedef unsigned __int64       uint64;
+#   else
+     typedef long long              int64;
+     typedef unsigned long long     uint64;
+#   endif
+    typedef unsigned char           uchar;
+    typedef unsigned short          unichar;
+    typedef int32                   status_t;
+#  endif  /* !MUSCLE_TYPES_PREDEFINED */
+# endif  /* !__ATHEOS__*/
+#endif  /* __BEOS__*/
+
+#define MAKETYPE(x) ((((unsigned long)(x[0])) << 24) | \
+                     (((unsigned long)(x[1])) << 16) | \
+                     (((unsigned long)(x[2])) <<  8) | \
+                     (((unsigned long)(x[3])) <<  0))
+
+#ifndef __BEOS__
+/* Be-style message-field type codes.
+ * I've calculated the integer equivalents for these codes
+ * because gcc whines like a little girl about the four-byte
+ * constants when compiling under Linux --jaf
+ */
+enum {
+   B_ANY_TYPE     = 1095653716, /* 'ANYT' = wild card                                   */
+   B_BOOL_TYPE    = 1112493900, /* 'BOOL' = boolean (1 byte per bool)                   */
+   B_DOUBLE_TYPE  = 1145195589, /* 'DBLE' = double-precision float (8 bytes per double) */
+   B_FLOAT_TYPE   = 1179406164, /* 'FLOT' = single-precision float (4 bytes per float)  */
+   B_INT64_TYPE   = 1280069191, /* 'LLNG' = long long integer (8 bytes per int)         */
+   B_INT32_TYPE   = 1280265799, /* 'LONG' = long integer (4 bytes per int)              */
+   B_INT16_TYPE   = 1397248596, /* 'SHRT' = short integer (2 bytes per int)             */
+   B_INT8_TYPE    = 1113150533, /* 'BYTE' = byte integer (1 byte per int)               */
+   B_MESSAGE_TYPE = 1297303367, /* 'MSGG' = sub Message objects (reference counted)     */
+   B_POINTER_TYPE = 1347310674, /* 'PNTR' = pointers (will not be flattened)            */
+   B_POINT_TYPE   = 1112559188, /* 'BPNT' = Point objects (each Point has two floats)   */
+   B_RECT_TYPE    = 1380270932, /* 'RECT' = Rect objects (each Rect has four floats)    */
+   B_STRING_TYPE  = 1129534546, /* 'CSTR' = String objects (variable length)            */
+   B_OBJECT_TYPE  = 1330664530, /* 'OPTR' = Flattened user objects (obsolete)           */
+   B_RAW_TYPE     = 1380013908, /* 'RAWT' = Raw data (variable number of bytes)         */
+   B_MIME_TYPE    = 1296649541  /* 'MIME' = MIME strings (obsolete)                     */
+};
+#endif
+
+/* This one isn't defined by BeOS, so we have to enumerate it separately.               */
+enum {
+   B_TAG_TYPE     = 1297367367  /* 'MTAG' = new for v2.00; for in-mem-only tags         */
+};
+
+/* This constant is used in various places to mean 'as much as you want' */
+#define MUSCLE_NO_LIMIT ((uint32)-1)
+
+#ifdef __cplusplus
+
+/** A handy little method to swap the bytes of any int-style datatype around */
+template<typename T> inline T muscleSwapBytes(T swapMe)
+{
+   T retVal;
+   const uint8 * readFrom = (const uint8 *) &swapMe;
+   uint8 * writeTo  = ((uint8 *) &retVal)+sizeof(retVal);
+   for (uint32 i=0; i<sizeof(swapMe); i++) {*(--writeTo) = *(readFrom++);}
+   return retVal;
+}
+
+/* This template safely copies a value in from an untyped byte buffer to a typed value.
+ * (Make sure MUSCLE_CPU_REQUIRES_DATA_ALIGNMENT is defined if you are on a CPU
+ * that doesn't like non-word-aligned data reads and writes)
+ */
+template<typename T> inline void muscleCopyIn(T & dest, const void * source)
+{
+#ifdef MUSCLE_CPU_REQUIRES_DATA_ALIGNMENT
+   memcpy(&dest, source, sizeof(dest));
+#else
+   dest = *((const T*)source);
+#endif
+}
+
+/** This template safely copies a value in from a typed value to an untyped byte buffer.
+  * (Make sure MUSCLE_CPU_REQUIRES_DATA_ALIGNMENT is defined if you are on a CPU
+  *  that doesn't like non-word-aligned data reads and writes)
+  */
+template<typename T> inline void muscleCopyOut(void * dest, const T & source)
+{
+#ifdef MUSCLE_CPU_REQUIRES_DATA_ALIGNMENT
+   memcpy(dest, &source, sizeof(source));
+#else
+   *((T*)dest) = source;
+#endif
+}
+
+/** This macro should be used instead of "newnothrow T[count]".  It works the 
+  * same, except that it hacks around an ugly bug in gcc 3.x where newnothrow 
+  * would return ((T*)0x4) on memory failure instead of NULL.
+  * See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10300
+  */
+#if __GNUC__ == 3
+template <typename T> inline T * broken_gcc_newnothrow_array(size_t count)
+{
+   T * ret = newnothrow T[count];
+   return (ret <= (T *)(sizeof(void *))) ? NULL : ret;
+}
+# define newnothrow_array(T, count) broken_gcc_newnothrow_array<T>(count)
+#else
+# define newnothrow_array(T, count) newnothrow T[count]
+#endif
+
+/** Returns the smallest of the two arguments */
+template<typename T> inline const T & muscleMin(const T & p1, const T & p2) {return (p1 < p2) ? p1 : p2;}
+
+/** Returns the smallest of the three arguments */
+template<typename T> inline const T & muscleMin(const T & p1, const T & p2, const T & p3) {return muscleMin(p3, muscleMin(p1, p2));}
+
+/** Returns the smallest of the four arguments */
+template<typename T> inline const T & muscleMin(const T & p1, const T & p2, const T & p3, const T & p4) {return muscleMin(p3, p4, muscleMin(p1, p2));}
+
+/** Returns the smallest of the five arguments */
+template<typename T> inline const T & muscleMin(const T & p1, const T & p2, const T & p3, const T & p4, const T & p5) {return muscleMin(p3, p4, p5, muscleMin(p1, p2));}
+
+/** Returns the largest of the two arguments */
+template<typename T> inline const T & muscleMax(const T & p1, const T & p2) {return (p1 < p2) ? p2 : p1;}
+
+/** Returns the largest of the three arguments */
+template<typename T> inline const T & muscleMax(const T & p1, const T & p2, const T & p3) {return muscleMax(p3, muscleMax(p1, p2));}
+
+/** Returns the largest of the four arguments */
+template<typename T> inline const T & muscleMax(const T & p1, const T & p2, const T & p3, const T & p4) {return muscleMax(p3, p4, muscleMax(p1, p2));}
+
+/** Returns the largest of the five arguments */
+template<typename T> inline const T & muscleMax(const T & p1, const T & p2, const T & p3, const T & p4, const T & p5) {return muscleMax(p3, p4, p5, muscleMax(p1, p2));}
+
+/** Swaps the two arguments */
+template<typename T> inline void muscleSwap(T & p1, T & p2) {T t = p1; p1 = p2; p2 = t;}
+
+/** Returns the value nearest to (v) that is still in the range [lo, hi]. */
+template<typename T> inline const T & muscleClamp(const T & v, const T & lo, const T & hi) {return (v < lo) ? lo : ((v > hi) ? hi : v);}
+
+/** Returns true iff (v) is in the range [lo,hi]. */
+template<typename T> inline bool muscleInRange(const T & v, const T & lo, const T & hi) {return ((v >= lo)&&(v <= hi));}
+
+/** Returns -1 if arg1 is larger, or 1 if arg2 is larger, or 0 if they are equal. */
+template<typename T> inline int muscleCompare(const T & arg1, const T & arg2) {return (arg1>arg2) ? 1 : ((arg1<arg2) ? -1 : 0);}
+
+/** Returns the absolute value of (arg) */
+template<typename T> inline T muscleAbs(const T & arg) {return (arg<0)?(-arg):arg;}
+
+/** Rounds the given float to the nearest integer value. */
+inline int muscleRintf(float f) {return (f>=0.0f) ? ((int)(f+0.5f)) : -((int)((-f)+0.5f));}
+
+/** Returns -1 if the value is less than zero, +1 if it is greater than zero, or 0 otherwise. */
+template<typename T> inline int muscleSgn(const T & arg) {return (arg<0)?-1:((arg>0)?1:0);}
+
+#endif  /* __cplusplus */
+
+#ifndef __BEOS__
+
+/*
+ * Copyright(c) 1983,   1989
+ *    The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ *      from nameser.h  8.1 (Berkeley) 6/2/93
+ *      $Id$
+ */
+
+#ifndef BYTE_ORDER
+  #if (BSD >= 199103)
+    #include <machine/endian.h>
+  #else
+    #ifdef linux
+      #include <endian.h>
+    #else
+      #define LITTLE_ENDIAN   1234    /* least-significant byte first (vax, pc) */
+      #define BIG_ENDIAN      4321    /* most-significant byte first (IBM, net) */
+
+      #if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
+              defined(__i386) || defined(__ia64) || \
+              defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
+              defined(__alpha__) || defined(__alpha) || defined(__CYGWIN__) || \
+              defined(_M_IX86) || defined(__GNUWIN32__) || defined(__LITTLEENDIAN__) || \
+              (defined(__Lynx__) && defined(__x86__))
+        #define BYTE_ORDER      LITTLE_ENDIAN
+      #endif
+
+      #if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+          defined(__sparc) || \
+          defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+          defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
+          defined(apollo) || defined(__convex__) || defined(_CRAY) || \
+          defined(__hppa) || defined(__hp9000) || \
+          defined(__hp9000s300) || defined(__hp9000s700) || \
+          defined(__hp3000s900) || defined(MPE) || \
+          defined(BIT_ZERO_ON_LEFT) || defined(m68k) || \
+              (defined(__Lynx__) && \
+              (defined(__68k__) || defined(__sparc__) || defined(__powerpc__)))
+        #define BYTE_ORDER      BIG_ENDIAN
+      #endif
+    #endif /* linux */
+  #endif /* BSD */
+#endif /* BYTE_ORDER */
+
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN) 
+        /*
+         * you must determine what the correct bit order is for
+         * your compiler - the next line is an intentional error
+         * which will force your compiles to bomb until you fix
+         * the above macros.
+         */
+        error "Undefined or invalid BYTE_ORDER";
+#endif
+
+/* End replacement code from Sun/University of California */
+# if defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY)
+static inline uint16 MusclePowerPCSwapInt16(uint16 val)
+{
+   uint16 a;
+   uint16 * addr = &a;
+   __asm__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
+   return a;
+}
+static inline uint32 MusclePowerPCSwapInt32(uint32 val)
+{
+   uint32 a;
+   uint32 * addr = &a;
+   __asm__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
+   return a;
+}
+static inline float MusclePowerPCSwapFloat(float val)
+{
+   float a;
+   float * addr = &a;
+   __asm__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
+   return a;
+}
+static inline uint64 MusclePowerPCSwapInt64(uint64 val)
+{
+   return ((uint64)(MusclePowerPCSwapInt32((uint32)((val>>32)&0xFFFFFFFF))))|(((uint64)(MusclePowerPCSwapInt32((uint32)(val&0xFFFFFFFF))))<<32);
+}
+static inline double MusclePowerPCSwapDouble(double val)
+{
+   uint64 v64 = MusclePowerPCSwapInt64(*((uint64 *)&val));
+   return *((double *)&v64);
+}
+#  define B_SWAP_DOUBLE(arg)   MusclePowerPCSwapDouble((double)(arg))
+#  define B_SWAP_FLOAT(arg)    MusclePowerPCSwapFloat((float)(arg))
+#  define B_SWAP_INT64(arg)    MusclePowerPCSwapInt64((uint64)(arg))
+#  define B_SWAP_INT32(arg)    MusclePowerPCSwapInt32((uint32)(arg))
+#  define B_SWAP_INT16(arg)    MusclePowerPCSwapInt16((uint16)(arg))
+# elif defined(MUSCLE_USE_X86_INLINE_ASSEMBLY)
+static inline uint16 MuscleX86SwapInt16(uint16 val)
+{
+#ifdef _MSC_VER
+   __asm {
+      mov ax, val;
+      xchg al, ah;
+      mov val, ax;
+   };
+#else
+   __asm__ ("xchgb %b0,%h0" : "=q" (val) : "0" (val));
+#endif
+   return val;
+}
+static inline uint32 MuscleX86SwapInt32(uint32 val)
+{
+#ifdef _MSC_VER
+   __asm {
+      mov eax, val;
+      bswap eax;
+      mov val, eax;
+   };
+#else
+   __asm__ ("bswap %0" : "+r" (val));
+#endif
+   return val;
+}
+static inline float MuscleX86SwapFloat(float val)
+{
+#ifdef _MSC_VER
+   __asm {
+      mov eax, val;
+      bswap eax;
+      mov val, eax;
+   };
+#else
+   __asm__ ("bswap %0" : "+r" (val));
+#endif
+   return val;
+}
+static inline uint64 MuscleX86SwapInt64(uint64 val)
+{
+#ifdef _MSC_VER
+   __asm {
+      mov eax, DWORD PTR val;
+      mov edx, DWORD PTR val + 4;
+      bswap eax;
+      bswap edx;
+      mov DWORD PTR val, edx;
+      mov DWORD PTR val + 4, eax;
+   };
+   return val;
+#else
+   return ((uint64)(MuscleX86SwapInt32((uint32)((val>>32)&0xFFFFFFFF))))|(((uint64)(MuscleX86SwapInt32((uint32)(val&0xFFFFFFFF))))<<32);
+#endif
+}
+static inline double MuscleX86SwapDouble(double val)
+{
+#ifdef _MSC_VER
+   __asm {
+      mov eax, DWORD PTR val;
+      mov edx, DWORD PTR val + 4;
+      bswap eax;
+      bswap edx;
+      mov DWORD PTR val, edx;
+      mov DWORD PTR val + 4, eax;
+   };
+   return val;
+#else
+   uint64 v64 = MuscleX86SwapInt64(*((uint64 *)&val));
+   return *((double *)&v64);
+#endif
+}
+#  define B_SWAP_DOUBLE(arg)   MuscleX86SwapDouble((double)(arg))
+#  define B_SWAP_FLOAT(arg)    MuscleX86SwapFloat((float)(arg))
+#  define B_SWAP_INT64(arg)    MuscleX86SwapInt64((uint64)(arg))
+#  define B_SWAP_INT32(arg)    MuscleX86SwapInt32((uint32)(arg))
+#  define B_SWAP_INT16(arg)    MuscleX86SwapInt16((uint16)(arg))
+# else
+#  define B_SWAP_DOUBLE(arg)   muscleSwapBytes((double)(arg))
+#  define B_SWAP_FLOAT(arg)    muscleSwapBytes((float)(arg))
+#  define B_SWAP_INT64(arg)    muscleSwapBytes((uint64)(arg))
+#  define B_SWAP_INT32(arg)    muscleSwapBytes((uint32)(arg))
+#  define B_SWAP_INT16(arg)    muscleSwapBytes((uint16)(arg))
+# endif
+# if BYTE_ORDER == LITTLE_ENDIAN
+#  define B_HOST_IS_LENDIAN 1
+#  define B_HOST_IS_BENDIAN 0
+#  define B_HOST_TO_LENDIAN_DOUBLE(arg) ((double)(arg))
+#  define B_HOST_TO_LENDIAN_FLOAT(arg)  ((float)(arg))
+#  define B_HOST_TO_LENDIAN_INT64(arg)  ((uint64)(arg))
+#  define B_HOST_TO_LENDIAN_INT32(arg)  ((uint32)(arg))
+#  define B_HOST_TO_LENDIAN_INT16(arg)  ((uint16)(arg))
+#  define B_HOST_TO_BENDIAN_DOUBLE(arg) B_SWAP_DOUBLE(arg)
+#  define B_HOST_TO_BENDIAN_FLOAT(arg)  B_SWAP_FLOAT(arg)
+#  define B_HOST_TO_BENDIAN_INT64(arg)  B_SWAP_INT64(arg)
+#  define B_HOST_TO_BENDIAN_INT32(arg)  B_SWAP_INT32(arg)
+#  define B_HOST_TO_BENDIAN_INT16(arg)  B_SWAP_INT16(arg)
+#  define B_LENDIAN_TO_HOST_DOUBLE(arg) ((double)(arg))
+#  define B_LENDIAN_TO_HOST_FLOAT(arg)  ((float)(arg))
+#  define B_LENDIAN_TO_HOST_INT64(arg)  ((uint64)(arg))
+#  define B_LENDIAN_TO_HOST_INT32(arg)  ((uint32)(arg))
+#  define B_LENDIAN_TO_HOST_INT16(arg)  ((uint16)(arg))
+#  define B_BENDIAN_TO_HOST_DOUBLE(arg) B_SWAP_DOUBLE(arg)
+#  define B_BENDIAN_TO_HOST_FLOAT(arg)  B_SWAP_FLOAT(arg)
+#  define B_BENDIAN_TO_HOST_INT64(arg)  B_SWAP_INT64(arg)
+#  define B_BENDIAN_TO_HOST_INT32(arg)  B_SWAP_INT32(arg)
+#  define B_BENDIAN_TO_HOST_INT16(arg)  B_SWAP_INT16(arg)
+# else /* LITTLE_ENDIAN */
+#  define B_HOST_IS_LENDIAN 0
+#  define B_HOST_IS_BENDIAN 1
+#  define B_HOST_TO_LENDIAN_DOUBLE(arg) B_SWAP_DOUBLE(arg)
+#  define B_HOST_TO_LENDIAN_FLOAT(arg)  B_SWAP_FLOAT(arg)
+#  define B_HOST_TO_LENDIAN_INT64(arg)  B_SWAP_INT64(arg)
+#  define B_HOST_TO_LENDIAN_INT32(arg)  B_SWAP_INT32(arg)
+#  define B_HOST_TO_LENDIAN_INT16(arg)  B_SWAP_INT16(arg)
+#  define B_HOST_TO_BENDIAN_DOUBLE(arg) ((double)(arg))
+#  define B_HOST_TO_BENDIAN_FLOAT(arg)  ((float)(arg))
+#  define B_HOST_TO_BENDIAN_INT64(arg)  ((uint64)(arg))
+#  define B_HOST_TO_BENDIAN_INT32(arg)  ((uint32)(arg))
+#  define B_HOST_TO_BENDIAN_INT16(arg)  ((uint16)(arg))
+#  define B_LENDIAN_TO_HOST_DOUBLE(arg) B_SWAP_DOUBLE(arg)
+#  define B_LENDIAN_TO_HOST_FLOAT(arg)  B_SWAP_FLOAT(arg)
+#  define B_LENDIAN_TO_HOST_INT64(arg)  B_SWAP_INT64(arg)
+#  define B_LENDIAN_TO_HOST_INT32(arg)  B_SWAP_INT32(arg)
+#  define B_LENDIAN_TO_HOST_INT16(arg)  B_SWAP_INT16(arg)
+#  define B_BENDIAN_TO_HOST_DOUBLE(arg) ((double)(arg))
+#  define B_BENDIAN_TO_HOST_FLOAT(arg)  ((float)(arg))
+#  define B_BENDIAN_TO_HOST_INT64(arg)  ((uint64)(arg))
+#  define B_BENDIAN_TO_HOST_INT32(arg)  ((uint32)(arg))
+#  define B_BENDIAN_TO_HOST_INT16(arg)  ((uint16)(arg))
+# endif /* !LITTLE_ENDIAN */
+#endif /* !__BEOS__ */
+
+/* Macro to turn a type code into a string representation.
+ * (typecode) is the type code to get the string for
+ * (buf) is a (char *) to hold the output string; it must be >= 5 bytes long.
+ */
+#define MakePrettyTypeCodeString(typecode, buf)                     \
+   {                                                                \
+      uint32 __bigEndian = B_HOST_TO_BENDIAN_INT32(typecode);       \
+      memcpy(buf, (const char *)&__bigEndian, sizeof(__bigEndian)); \
+      buf[sizeof(__bigEndian)] = '\0';                              \
+   }
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>     /* for errno */
+
+#ifdef WIN32
+# include <windows.h>
+# include <winsock.h>  /* for WSAGetLastError() */
+#endif
+
+#ifdef __cplusplus
+# include "syslog/SysLog.h"  /* for LogTime() */
+#endif  /* __cplusplus */
+
+/** Checks errno and returns true iff the last I/O operation
+  * failed because it would have had to block otherwise.
+  * NOTE:  Returns int so that it will compile even in C environments where no bool type is defined.
+  */
+static inline int PreviousOperationWouldBlock()
+{
+#ifdef WIN32
+   return (WSAGetLastError() == WSAEWOULDBLOCK);
+#else
+   return (errno == EWOULDBLOCK);
+#endif
+}
+
+/** Checks errno and returns true iff the last I/O operation
+  * failed because it was interrupted by a signal or etc.
+  * NOTE:  Returns int so that it will compile even in C environments where no bool type is defined.
+  */
+static inline int PreviousOperationWasInterrupted()
+{
+#ifdef WIN32
+   return (WSAGetLastError() == WSAEINTR);
+#else
+   return (errno == EINTR);
+#endif
+}
+
+/** This function applies semi-standard logic to convert the return value
+  * of a system I/O call and (errno) into a proper MUSCLE-standard return value.
+  * (A MUSCLE-standard return value's semantics are:  Negative on error,
+  * otherwise the return value is the number of bytes that were transferred)
+  * @param origRet The return value of the original system call (e.g. to read()/write()/send()/recv())
+  * @param maxSize The maximum number of bytes that the system call was permitted to send during that call.
+  * @param blocking True iff the socket/file descriptor is in blocking I/O mode.  (Type is int for C compatibility -- it's really a boolean parameter)
+  * @returns The system call's return value equivalent in MUSCLE return value semantics.
+  */
+static inline int32 ConvertReturnValueToMuscleSemantics(int origRet, uint32 maxSize, int blocking)
+{
+   int32 retForBlocking = ((origRet > 0)||(maxSize == 0)) ? origRet : -1;
+   return blocking ? retForBlocking : ((origRet<0)&&((PreviousOperationWouldBlock())||(PreviousOperationWasInterrupted()))) ? 0 : retForBlocking;
+}
+
+BEGIN_NAMESPACE(muscle);
+
+#if MUSCLE_TRACE_CHECKPOINTS > 0
+
+/** Exposed as an implementation detail.  Please ignore! */
+extern volatile uint32 * _muscleTraceValues;
+
+/** Exposed as an implementation detail.  Please ignore! */
+extern uint32 _muscleNextTraceValueIndex;
+
+/** Sets the location of the trace-checkpoints array to store trace checkpoints into.
+  * @param location A pointer to an array of at least (MUSCLE_TRACE_CHECKPOINTS) uint32s, or NULL.
+  *                 If NULL (or if this function is never called), the default array will be used.
+  */
+void SetTraceValuesLocation(volatile uint32 * location);
+
+/** Set this process's current trace value to (v).  This can be used as a primitive debugging tool, to determine
+  * where this process was last seen executing -- useful for determining where the process is spinning at.
+  * @note this function is a no-op if MUSCLE_TRACE_CHECKPOINTS is not defined to a value greater than zero.
+  */
+static inline void StoreTraceValue(uint32 v) 
+{
+   _muscleTraceValues[_muscleNextTraceValueIndex] = v;  /* store the current value */
+   _muscleNextTraceValueIndex                     = (_muscleNextTraceValueIndex+1)%MUSCLE_TRACE_CHECKPOINTS; /* move the pointer */
+   _muscleTraceValues[_muscleNextTraceValueIndex] = ((uint32)-1);  /* mark the next position with a special tag to show that it's next */
+}
+
+/** Returns a pointer to the first value in the trace-values array. */
+static inline const volatile uint32 * GetTraceValues() {return _muscleTraceValues;}
+
+/** A macro for automatically setting a trace checkpoint value based on current code location. 
+  * The value will be the two characters of the function or file name, left-shifted by 16 bits, 
+  * and then OR'd together with the current line number.  This should give the debugging person a 
+  * fairly good clue as to where the checkpoint was located, while still being very cheap to implement.
+  *
+  * @note This function will be a no-op unless MUSCLE_TRACE_CHECKPOINTS is defined to be greater than zero.
+  */
+#if defined(__GNUC__)
+#define TCHECKPOINT                                   \
+{                                                     \
+   const char * d = __FUNCTION__;                     \
+   StoreTraceValue((d[0]<<24)|(d[1]<<16)|(__LINE__)); \
+}
+#else
+#define TCHECKPOINT                                   \
+{                                                     \
+   const char * d = __FILE__;                         \
+   StoreTraceValue((d[0]<<24)|(d[1]<<16)|(__LINE__)); \
+}
+#endif
+
+#else
+/* no-op implementations for when we aren't using the trace facility */
+static inline void SetTraceValuesLocation(volatile uint32 * location) {(void) location;}  /* named param is necessary for C compatibility */
+static inline void StoreTraceValue(uint32 v) {(void) v;}  /* named param is necessary for C compatibility */
+#define TCHECKPOINT {/* empty */}
+#endif
+
+END_NAMESPACE(muscle);
+
+#endif /* _MUSCLE_SUPPORT_H */