relicense to 0BSD
[pforth] / csrc / pf_mem.c
index 4cdd94d..fed36eb 100644 (file)
-/***************************************************************\r
-** Memory allocator for systems that don't have real one.\r
-** This might be useful when bringing up a new computer with no OS.\r
-**\r
-** For PForth based on 'C'\r
-**\r
-** Author: Phil Burk\r
-** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom\r
-**\r
-** The pForth software code is dedicated to the public domain,\r
-** and any third party may reproduce, distribute and modify\r
-** the pForth software code or any derivative works thereof\r
-** without any compensation or license.  The pForth software\r
-** code is provided on an "as is" basis without any warranty\r
-** of any kind, including, without limitation, the implied\r
-** warranties of merchantability and fitness for a particular\r
-** purpose and their equivalents under the laws of any jurisdiction.\r
-**\r
-****************************************************************\r
-**\r
-***************************************************************/\r
-\r
-#include "pf_all.h"\r
-\r
-\r
-#ifdef PF_NO_MALLOC\r
-\r
-static char  *gMemPoolPtr;\r
-static ucell_t gMemPoolSize;\r
-\r
-/* CUSTOM: Make the memory pool bigger if you want. */\r
-#ifndef PF_MEM_POOL_SIZE\r
-       #define PF_MEM_POOL_SIZE (0x100000)\r
-#endif\r
-\r
-#define PF_MEM_BLOCK_SIZE (16)\r
-\r
-#ifndef PF_MALLOC_ADDRESS\r
-       static char MemoryPool[PF_MEM_POOL_SIZE];\r
-       #define PF_MALLOC_ADDRESS MemoryPool\r
-#endif\r
-\r
-/**********************************************************\r
-** Doubly Linked List Tools\r
-**********************************************************/\r
-\r
-typedef struct DoublyLinkedListNode_s\r
-{\r
-       struct DoublyLinkedListNode_s *dlln_Next;\r
-       struct DoublyLinkedListNode_s *dlln_Previous;\r
-} DoublyLinkedListNode;\r
-\r
-typedef struct DoublyLinkedList_s\r
-{\r
-       DoublyLinkedListNode *dll_First;\r
-       DoublyLinkedListNode *dll_Null;\r
-       DoublyLinkedListNode *dll_Last;\r
-} DoublyLinkedList;\r
-\r
-#define dllPreviousNode(n) ((n)->dlln_Previous)\r
-#define dllNextNode(n) ((n)->dlln_Next)\r
-\r
-void dllSetupList( DoublyLinkedList *dll )\r
-{\r
-       dll->dll_First = &(dll->dll_Null);\r
-       dll->dll_Null = (DoublyLinkedListNode *) NULL;\r
-       dll->dll_Last = &(dll->dll_First);\r
-}\r
-\r
-void dllLinkNodes( DoublyLinkedListNode *Node0, DoublyLinkedListNode *Node1 )\r
-{\r
-       Node0->dlln_Next = Node1;\r
-       Node1->dlln_Previous = Node0;\r
-}\r
-\r
-void dllInsertNodeBefore( DoublyLinkedListNode *NewNodePtr,\r
-       DoublyLinkedListNode *NodeInListPtr )\r
-{\r
-       DoublyLinkedListNode *NodePreviousPtr = dllPreviousNode( NodeInListPtr );\r
-       dllLinkNodes( NodePreviousPtr, NewNodePtr );\r
-       dllLinkNodes( NewNodePtr, NodeInListPtr );\r
-}\r
-\r
-void dllInsertNodeAfter( DoublyLinkedListNode *NewNodePtr,\r
-       DoublyLinkedListNode *NodeInListPtr )\r
-{\r
-       DoublyLinkedListNode *NodeNextPtr = dllNextNode( NodeInListPtr );\r
-       dllLinkNodes( NodeInListPtr, NewNodePtr );\r
-       dllLinkNodes( NewNodePtr, NodeNextPtr );\r
-}\r
-\r
-void dllDumpNode( DoublyLinkedListNode *NodePtr )\r
-{\r
-       TOUCH(NodePtr);\r
-       DBUG(("  0x%x -> (0x%x) -> 0x%x\n",\r
-               dllPreviousNode( NodePtr ), NodePtr,\r
-               dllNextNode( NodePtr ) ));\r
-}\r
-\r
-cell_t dllCheckNode( DoublyLinkedListNode *NodePtr )\r
-{\r
-       if( (NodePtr->dlln_Next->dlln_Previous != NodePtr) ||\r
-           (NodePtr->dlln_Previous->dlln_Next != NodePtr))\r
-       {\r
-               ERR("dllCheckNode: Bad Node!\n");\r
-               dllDumpNode( dllPreviousNode( NodePtr ) );\r
-               dllDumpNode( NodePtr );\r
-               dllDumpNode( dllNextNode( NodePtr ) );\r
-               return -1;\r
-       }\r
-       else\r
-       {\r
-               return 0;\r
-       }\r
-}\r
-void dllRemoveNode( DoublyLinkedListNode *NodePtr )\r
-{\r
-       if( dllCheckNode( NodePtr ) == 0 )\r
-       {\r
-               dllLinkNodes( dllPreviousNode( NodePtr ), dllNextNode( NodePtr ) );\r
-       }\r
-}\r
-\r
-void dllAddNodeToHead( DoublyLinkedList *ListPtr, DoublyLinkedListNode *NewNodePtr )\r
-{\r
-       dllInsertNodeBefore( NewNodePtr, ListPtr->dll_First );\r
-}\r
-\r
-void dllAddNodeToTail( DoublyLinkedList *ListPtr, DoublyLinkedListNode *NewNodePtr )\r
-{\r
-       dllInsertNodeAfter( NewNodePtr, ListPtr->dll_Last );\r
-}\r
-\r
-#define dllIsNodeInList( n ) (!((n)->dlln_Next == NULL) )\r
-#define dllIsLastNode( n ) ((n)->dlln_Next->dll_nNext == NULL )\r
-#define dllIsListEmpty( l ) ((l)->dll_First == ((DoublyLinkedListNode *) &((l)->dll_Null)) )\r
-#define dllFirstNode( l ) ((l)->dll_First)\r
-\r
-static DoublyLinkedList gMemList;\r
-\r
-typedef struct MemListNode\r
-{\r
-       DoublyLinkedListNode  mln_Node;\r
-       cell_t                 mln_Size;\r
-} MemListNode;\r
-\r
-#ifdef PF_DEBUG\r
-/***************************************************************\r
-** Dump memory list.\r
-*/\r
-void maDumpList( void )\r
-{\r
-       MemListNode *mln;\r
-       \r
-       MSG("PForth MemList\n");\r
-       \r
-       for( mln = (MemListNode *) dllFirstNode( &gMemList );\r
-            dllIsNodeInList( (DoublyLinkedListNode *) mln);\r
-                mln = (MemListNode *) dllNextNode( (DoublyLinkedListNode *) mln ) )\r
-       {\r
-               MSG("  Node at = 0x"); ffDotHex(mln);\r
-               MSG_NUM_H(", size = 0x", mln->mln_Size);\r
-       }\r
-}\r
-#endif\r
-\r
-\r
-/***************************************************************\r
-** Free mem of any size.\r
-*/\r
-static void pfFreeRawMem( char *Mem, cell_t NumBytes )\r
-{\r
-       MemListNode *mln, *FreeNode;\r
-       MemListNode *AdjacentLower = NULL;\r
-       MemListNode *AdjacentHigher = NULL;\r
-       MemListNode *NextBiggest = NULL;\r
-       \r
-/* Allocate in whole blocks of 16 bytes */\r
-       DBUG(("\npfFreeRawMem( 0x%x, 0x%x )\n", Mem, NumBytes ));\r
-       NumBytes = (NumBytes + PF_MEM_BLOCK_SIZE - 1) & ~(PF_MEM_BLOCK_SIZE - 1);\r
-       DBUG(("\npfFreeRawMem: Align NumBytes to 0x%x\n", NumBytes ));\r
-       \r
-/* Check memory alignment. */\r
-       if( ( ((cell_t)Mem) & (PF_MEM_BLOCK_SIZE - 1)) != 0)\r
-       {\r
-               MSG_NUM_H("pfFreeRawMem: misaligned Mem = 0x", (cell_t) Mem );\r
-               return;\r
-       }\r
-       \r
-/* Scan list from low to high looking for various nodes. */\r
-       for( mln = (MemListNode *) dllFirstNode( &gMemList );\r
-            dllIsNodeInList( (DoublyLinkedListNode *) mln);\r
-                mln = (MemListNode *) dllNextNode( (DoublyLinkedListNode *) mln ) )\r
-       {\r
-               if( (((char *) mln) + mln->mln_Size) == Mem )\r
-               {\r
-                       AdjacentLower = mln;\r
-               }\r
-               else if( ((char *) mln) == ( Mem + NumBytes ))\r
-               {\r
-                       AdjacentHigher = mln;\r
-               }\r
-/* is this the next biggest node. */\r
-               else if( (NextBiggest == NULL) && (mln->mln_Size >= NumBytes) )\r
-               {\r
-                       NextBiggest = mln;\r
-               }\r
-       }\r
-       \r
-/* Check to see if we can merge nodes. */\r
-       if( AdjacentHigher )\r
-       {\r
-DBUG((" Merge (0x%x) -> 0x%x\n", Mem, AdjacentHigher ));\r
-               NumBytes += AdjacentHigher->mln_Size;\r
-               dllRemoveNode( (DoublyLinkedListNode *) AdjacentHigher );\r
-       }\r
-       if( AdjacentLower )\r
-       {\r
-DBUG((" Merge 0x%x -> (0x%x)\n", AdjacentLower, Mem ));\r
-               AdjacentLower->mln_Size += NumBytes;\r
-       }\r
-       else\r
-       {\r
-DBUG((" Link before 0x%x\n", NextBiggest ));\r
-               FreeNode = (MemListNode *) Mem;\r
-               FreeNode->mln_Size = NumBytes;\r
-               if( NextBiggest == NULL )\r
-               {\r
-/* Nothing bigger so add to end of list. */\r
-                       dllAddNodeToTail( &gMemList, (DoublyLinkedListNode *) FreeNode );\r
-               }\r
-               else\r
-               {\r
-/* Add this node before the next biggest one we found. */\r
-                       dllInsertNodeBefore( (DoublyLinkedListNode *) FreeNode,\r
-                               (DoublyLinkedListNode *) NextBiggest );\r
-               }\r
-       }\r
-       \r
-/*     maDumpList(); */\r
-}\r
-\r
-\r
-\r
-/***************************************************************\r
-** Setup memory list. Initialize allocator.\r
-*/\r
-static void pfInitMemBlock( void *addr, ucell_t poolSize )\r
-{\r
-       char *AlignedMemory;\r
-       cell_t AlignedSize;\r
-\r
-       pfDebugMessage("pfInitMemBlock()\n");\r
-/* Set globals. */\r
-       gMemPoolPtr = addr;\r
-       gMemPoolSize = poolSize;\r
-       \r
-       dllSetupList( &gMemList );\r
-       \r
-/* Adjust to next highest aligned memory location. */\r
-       AlignedMemory = (char *) ((((cell_t)gMemPoolPtr) + PF_MEM_BLOCK_SIZE - 1) &\r
-                         ~(PF_MEM_BLOCK_SIZE - 1));\r
-                                         \r
-/* Adjust size to reflect aligned memory. */\r
-       AlignedSize = gMemPoolSize - (AlignedMemory - gMemPoolPtr);\r
-       \r
-/* Align size of pool. */\r
-       AlignedSize = AlignedSize & ~(PF_MEM_BLOCK_SIZE - 1);\r
-       \r
-/* Free to pool. */\r
-       pfFreeRawMem( AlignedMemory, AlignedSize );\r
-       \r
-}\r
-\r
-/***************************************************************\r
-** Allocate mem from list of free nodes.\r
-*/\r
-static char *pfAllocRawMem( cell_t NumBytes )\r
-{\r
-       char *Mem = NULL;\r
-       MemListNode *mln;\r
-       pfDebugMessage("pfAllocRawMem()\n");\r
-       \r
-       if( NumBytes <= 0 ) return NULL;\r
-       \r
-/* Allocate in whole blocks of 16 bytes */\r
-       NumBytes = (NumBytes + PF_MEM_BLOCK_SIZE - 1) & ~(PF_MEM_BLOCK_SIZE - 1);\r
-       \r
-       DBUG(("\npfAllocRawMem( 0x%x )\n", NumBytes ));\r
-       \r
-/* Scan list from low to high until we find a node big enough. */\r
-       for( mln = (MemListNode *) dllFirstNode( &gMemList );\r
-            dllIsNodeInList( (DoublyLinkedListNode *) mln);\r
-                mln = (MemListNode *) dllNextNode( (DoublyLinkedListNode *) mln ) )\r
-       {\r
-               if( mln->mln_Size >= NumBytes )\r
-               {\r
-                       cell_t RemSize;\r
-\r
-                       Mem = (char *) mln;\r
-                       \r
-/* Remove this node from list. */\r
-                       dllRemoveNode( (DoublyLinkedListNode *) mln );\r
-                       \r
-/* Is there enough left in block to make it worth splitting? */\r
-                       RemSize = mln->mln_Size - NumBytes;\r
-                       if( RemSize >= PF_MEM_BLOCK_SIZE )\r
-                       {\r
-                               pfFreeRawMem( (Mem + NumBytes), RemSize );\r
-                       }\r
-                       break;\r
-               }\r
-                               \r
-       }\r
-/*     maDumpList(); */\r
-       DBUG(("Allocate mem at 0x%x.\n", Mem ));\r
-       return Mem;\r
-}\r
-\r
-/***************************************************************\r
-** Keep mem size at first cell.\r
-*/\r
-char *pfAllocMem( cell_t NumBytes )\r
-{\r
-       cell_t *IntMem;\r
-       \r
-       if( NumBytes <= 0 ) return NULL;\r
-       \r
-/* Allocate an extra cell for size. */\r
-       NumBytes += sizeof(cell_t);\r
-       \r
-       IntMem = (cell_t *)pfAllocRawMem( NumBytes );\r
-       \r
-       if( IntMem != NULL ) *IntMem++ = NumBytes;\r
-       \r
-       return (char *) IntMem;\r
-}\r
-\r
-/***************************************************************\r
-** Free mem with mem size at first cell.\r
-*/\r
-void pfFreeMem( void *Mem )\r
-{\r
-       cell_t *IntMem;\r
-       cell_t NumBytes;\r
-       \r
-       if( Mem == NULL ) return;\r
-       \r
-/* Allocate an extra cell for size. */\r
-       IntMem = (cell_t *) Mem;\r
-       IntMem--;\r
-       NumBytes = *IntMem;\r
-       \r
-       pfFreeRawMem( (char *) IntMem, NumBytes );\r
-       \r
-}\r
-\r
-void pfInitMemoryAllocator( void )\r
-{\r
-       pfInitMemBlock( PF_MALLOC_ADDRESS, PF_MEM_POOL_SIZE );\r
-}\r
-#else /* PF_NO_MALLOC */\r
-\r
-int not_an_empty_file;  /* Stops nasty compiler warnings when PF_NO_MALLOC not defined. */\r
-\r
-#endif /* PF_NO_MALLOC */\r
+/***************************************************************
+** Memory allocator for systems that don't have real one.
+** This might be useful when bringing up a new computer with no OS.
+**
+** For PForth based on 'C'
+**
+** Author: Phil Burk
+** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom
+**
+** Permission to use, copy, modify, and/or distribute this
+** software for any purpose with or without fee is hereby granted.
+**
+** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+** THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+** FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**
+****************************************************************
+**
+***************************************************************/
+
+#include "pf_all.h"
+
+
+#ifdef PF_NO_MALLOC
+
+static char  *gMemPoolPtr;
+static ucell_t gMemPoolSize;
+
+/* CUSTOM: Make the memory pool bigger if you want. */
+#ifndef PF_MEM_POOL_SIZE
+    #define PF_MEM_POOL_SIZE (0x100000)
+#endif
+
+#define PF_MEM_BLOCK_SIZE (16)
+
+#ifndef PF_MALLOC_ADDRESS
+    static char MemoryPool[PF_MEM_POOL_SIZE];
+    #define PF_MALLOC_ADDRESS MemoryPool
+#endif
+
+/**********************************************************
+** Doubly Linked List Tools
+**********************************************************/
+
+typedef struct DoublyLinkedListNode_s
+{
+    struct DoublyLinkedListNode_s *dlln_Next;
+    struct DoublyLinkedListNode_s *dlln_Previous;
+} DoublyLinkedListNode;
+
+typedef struct DoublyLinkedList_s
+{
+    DoublyLinkedListNode *dll_First;
+    DoublyLinkedListNode *dll_Null;
+    DoublyLinkedListNode *dll_Last;
+} DoublyLinkedList;
+
+#define dllPreviousNode(n) ((n)->dlln_Previous)
+#define dllNextNode(n) ((n)->dlln_Next)
+
+void dllSetupList( DoublyLinkedList *dll )
+{
+    dll->dll_First = &(dll->dll_Null);
+    dll->dll_Null = (DoublyLinkedListNode *) NULL;
+    dll->dll_Last = &(dll->dll_First);
+}
+
+void dllLinkNodes( DoublyLinkedListNode *Node0, DoublyLinkedListNode *Node1 )
+{
+    Node0->dlln_Next = Node1;
+    Node1->dlln_Previous = Node0;
+}
+
+void dllInsertNodeBefore( DoublyLinkedListNode *NewNodePtr,
+    DoublyLinkedListNode *NodeInListPtr )
+{
+    DoublyLinkedListNode *NodePreviousPtr = dllPreviousNode( NodeInListPtr );
+    dllLinkNodes( NodePreviousPtr, NewNodePtr );
+    dllLinkNodes( NewNodePtr, NodeInListPtr );
+}
+
+void dllInsertNodeAfter( DoublyLinkedListNode *NewNodePtr,
+    DoublyLinkedListNode *NodeInListPtr )
+{
+    DoublyLinkedListNode *NodeNextPtr = dllNextNode( NodeInListPtr );
+    dllLinkNodes( NodeInListPtr, NewNodePtr );
+    dllLinkNodes( NewNodePtr, NodeNextPtr );
+}
+
+void dllDumpNode( DoublyLinkedListNode *NodePtr )
+{
+    TOUCH(NodePtr);
+    DBUG(("  0x%x -> (0x%x) -> 0x%x\n",
+        dllPreviousNode( NodePtr ), NodePtr,
+        dllNextNode( NodePtr ) ));
+}
+
+cell_t dllCheckNode( DoublyLinkedListNode *NodePtr )
+{
+    if( (NodePtr->dlln_Next->dlln_Previous != NodePtr) ||
+        (NodePtr->dlln_Previous->dlln_Next != NodePtr))
+    {
+        ERR("dllCheckNode: Bad Node!\n");
+        dllDumpNode( dllPreviousNode( NodePtr ) );
+        dllDumpNode( NodePtr );
+        dllDumpNode( dllNextNode( NodePtr ) );
+        return -1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+void dllRemoveNode( DoublyLinkedListNode *NodePtr )
+{
+    if( dllCheckNode( NodePtr ) == 0 )
+    {
+        dllLinkNodes( dllPreviousNode( NodePtr ), dllNextNode( NodePtr ) );
+    }
+}
+
+void dllAddNodeToHead( DoublyLinkedList *ListPtr, DoublyLinkedListNode *NewNodePtr )
+{
+    dllInsertNodeBefore( NewNodePtr, ListPtr->dll_First );
+}
+
+void dllAddNodeToTail( DoublyLinkedList *ListPtr, DoublyLinkedListNode *NewNodePtr )
+{
+    dllInsertNodeAfter( NewNodePtr, ListPtr->dll_Last );
+}
+
+#define dllIsNodeInList( n ) (!((n)->dlln_Next == NULL) )
+#define dllIsLastNode( n ) ((n)->dlln_Next->dll_nNext == NULL )
+#define dllIsListEmpty( l ) ((l)->dll_First == ((DoublyLinkedListNode *) &((l)->dll_Null)) )
+#define dllFirstNode( l ) ((l)->dll_First)
+
+static DoublyLinkedList gMemList;
+
+typedef struct MemListNode
+{
+    DoublyLinkedListNode  mln_Node;
+    cell_t                 mln_Size;
+} MemListNode;
+
+#ifdef PF_DEBUG
+/***************************************************************
+** Dump memory list.
+*/
+void maDumpList( void )
+{
+    MemListNode *mln;
+
+    MSG("PForth MemList\n");
+
+    for( mln = (MemListNode *) dllFirstNode( &gMemList );
+         dllIsNodeInList( (DoublyLinkedListNode *) mln);
+         mln = (MemListNode *) dllNextNode( (DoublyLinkedListNode *) mln ) )
+    {
+        MSG("  Node at = 0x"); ffDotHex(mln);
+        MSG_NUM_H(", size = 0x", mln->mln_Size);
+    }
+}
+#endif
+
+
+/***************************************************************
+** Free mem of any size.
+*/
+static void pfFreeRawMem( char *Mem, cell_t NumBytes )
+{
+    MemListNode *mln, *FreeNode;
+    MemListNode *AdjacentLower = NULL;
+    MemListNode *AdjacentHigher = NULL;
+    MemListNode *NextBiggest = NULL;
+
+/* Allocate in whole blocks of 16 bytes */
+    DBUG(("\npfFreeRawMem( 0x%x, 0x%x )\n", Mem, NumBytes ));
+    NumBytes = (NumBytes + PF_MEM_BLOCK_SIZE - 1) & ~(PF_MEM_BLOCK_SIZE - 1);
+    DBUG(("\npfFreeRawMem: Align NumBytes to 0x%x\n", NumBytes ));
+
+/* Check memory alignment. */
+    if( ( ((cell_t)Mem) & (PF_MEM_BLOCK_SIZE - 1)) != 0)
+    {
+        MSG_NUM_H("pfFreeRawMem: misaligned Mem = 0x", (cell_t) Mem );
+        return;
+    }
+
+/* Scan list from low to high looking for various nodes. */
+    for( mln = (MemListNode *) dllFirstNode( &gMemList );
+         dllIsNodeInList( (DoublyLinkedListNode *) mln);
+         mln = (MemListNode *) dllNextNode( (DoublyLinkedListNode *) mln ) )
+    {
+        if( (((char *) mln) + mln->mln_Size) == Mem )
+        {
+            AdjacentLower = mln;
+        }
+        else if( ((char *) mln) == ( Mem + NumBytes ))
+        {
+            AdjacentHigher = mln;
+        }
+/* is this the next biggest node. */
+        else if( (NextBiggest == NULL) && (mln->mln_Size >= NumBytes) )
+        {
+            NextBiggest = mln;
+        }
+    }
+
+/* Check to see if we can merge nodes. */
+    if( AdjacentHigher )
+    {
+DBUG((" Merge (0x%x) -> 0x%x\n", Mem, AdjacentHigher ));
+        NumBytes += AdjacentHigher->mln_Size;
+        dllRemoveNode( (DoublyLinkedListNode *) AdjacentHigher );
+    }
+    if( AdjacentLower )
+    {
+DBUG((" Merge 0x%x -> (0x%x)\n", AdjacentLower, Mem ));
+        AdjacentLower->mln_Size += NumBytes;
+    }
+    else
+    {
+DBUG((" Link before 0x%x\n", NextBiggest ));
+        FreeNode = (MemListNode *) Mem;
+        FreeNode->mln_Size = NumBytes;
+        if( NextBiggest == NULL )
+        {
+/* Nothing bigger so add to end of list. */
+            dllAddNodeToTail( &gMemList, (DoublyLinkedListNode *) FreeNode );
+        }
+        else
+        {
+/* Add this node before the next biggest one we found. */
+            dllInsertNodeBefore( (DoublyLinkedListNode *) FreeNode,
+                (DoublyLinkedListNode *) NextBiggest );
+        }
+    }
+
+/*  maDumpList(); */
+}
+
+
+
+/***************************************************************
+** Setup memory list. Initialize allocator.
+*/
+static void pfInitMemBlock( void *addr, ucell_t poolSize )
+{
+    char *AlignedMemory;
+    cell_t AlignedSize;
+
+    pfDebugMessage("pfInitMemBlock()\n");
+/* Set globals. */
+    gMemPoolPtr = addr;
+    gMemPoolSize = poolSize;
+
+    dllSetupList( &gMemList );
+
+/* Adjust to next highest aligned memory location. */
+    AlignedMemory = (char *) ((((cell_t)gMemPoolPtr) + PF_MEM_BLOCK_SIZE - 1) &
+                      ~(PF_MEM_BLOCK_SIZE - 1));
+
+/* Adjust size to reflect aligned memory. */
+    AlignedSize = gMemPoolSize - (AlignedMemory - gMemPoolPtr);
+
+/* Align size of pool. */
+    AlignedSize = AlignedSize & ~(PF_MEM_BLOCK_SIZE - 1);
+
+/* Free to pool. */
+    pfFreeRawMem( AlignedMemory, AlignedSize );
+
+}
+
+/***************************************************************
+** Allocate mem from list of free nodes.
+*/
+static char *pfAllocRawMem( cell_t NumBytes )
+{
+    char *Mem = NULL;
+    MemListNode *mln;
+    pfDebugMessage("pfAllocRawMem()\n");
+
+    if( NumBytes <= 0 ) return NULL;
+
+/* Allocate in whole blocks of 16 bytes */
+    NumBytes = (NumBytes + PF_MEM_BLOCK_SIZE - 1) & ~(PF_MEM_BLOCK_SIZE - 1);
+
+    DBUG(("\npfAllocRawMem( 0x%x )\n", NumBytes ));
+
+/* Scan list from low to high until we find a node big enough. */
+    for( mln = (MemListNode *) dllFirstNode( &gMemList );
+         dllIsNodeInList( (DoublyLinkedListNode *) mln);
+         mln = (MemListNode *) dllNextNode( (DoublyLinkedListNode *) mln ) )
+    {
+        if( mln->mln_Size >= NumBytes )
+        {
+            cell_t RemSize;
+
+            Mem = (char *) mln;
+
+/* Remove this node from list. */
+            dllRemoveNode( (DoublyLinkedListNode *) mln );
+
+/* Is there enough left in block to make it worth splitting? */
+            RemSize = mln->mln_Size - NumBytes;
+            if( RemSize >= PF_MEM_BLOCK_SIZE )
+            {
+                pfFreeRawMem( (Mem + NumBytes), RemSize );
+            }
+            break;
+        }
+
+    }
+/*  maDumpList(); */
+    DBUG(("Allocate mem at 0x%x.\n", Mem ));
+    return Mem;
+}
+
+/***************************************************************
+** Keep mem size at first cell.
+*/
+char *pfAllocMem( cell_t NumBytes )
+{
+    cell_t *IntMem;
+
+    if( NumBytes <= 0 ) return NULL;
+
+/* Allocate an extra cell for size. */
+    NumBytes += sizeof(cell_t);
+
+    IntMem = (cell_t *)pfAllocRawMem( NumBytes );
+
+    if( IntMem != NULL ) *IntMem++ = NumBytes;
+
+    return (char *) IntMem;
+}
+
+/***************************************************************
+** Free mem with mem size at first cell.
+*/
+void pfFreeMem( void *Mem )
+{
+    cell_t *IntMem;
+    cell_t NumBytes;
+
+    if( Mem == NULL ) return;
+
+/* Allocate an extra cell for size. */
+    IntMem = (cell_t *) Mem;
+    IntMem--;
+    NumBytes = *IntMem;
+
+    pfFreeRawMem( (char *) IntMem, NumBytes );
+
+}
+
+void pfInitMemoryAllocator( void )
+{
+    pfInitMemBlock( PF_MALLOC_ADDRESS, PF_MEM_POOL_SIZE );
+}
+#else /* PF_NO_MALLOC */
+
+int not_an_empty_file;  /* Stops nasty compiler warnings when PF_NO_MALLOC not defined. */
+
+#endif /* PF_NO_MALLOC */