-/***************************************************************\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 uint32 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
-int32 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
- int32 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, int32 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( ( ((int32)Mem) & (PF_MEM_BLOCK_SIZE - 1)) != 0)\r
- {\r
- MSG_NUM_H("pfFreeRawMem: misaligned Mem = 0x", (int32) 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, uint32 poolSize )\r
-{\r
- char *AlignedMemory;\r
- int32 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 *) ((((int32)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( int32 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
- int32 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( int32 NumBytes )\r
-{\r
- int32 *IntMem;\r
- \r
- if( NumBytes <= 0 ) return NULL;\r
- \r
-/* Allocate an extra cell for size. */\r
- NumBytes += sizeof(int32);\r
- \r
- IntMem = (int32 *)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
- int32 *IntMem;\r
- int32 NumBytes;\r
- \r
- if( Mem == NULL ) return;\r
- \r
-/* Allocate an extra cell for size. */\r
- IntMem = (int32 *) 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
+**
+** The pForth software code is dedicated to the public domain,
+** and any third party may reproduce, distribute and modify
+** the pForth software code or any derivative works thereof
+** without any compensation or license. The pForth software
+** code is provided on an "as is" basis without any warranty
+** of any kind, including, without limitation, the implied
+** warranties of merchantability and fitness for a particular
+** purpose and their equivalents under the laws of any jurisdiction.
+**
+****************************************************************
+**
+***************************************************************/
+
+#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 */