]> 4ch.mooo.com Git - 16.git/blobdiff - 16/ID_MMw.C
clear
[16.git] / 16 / ID_MMw.C
diff --git a/16/ID_MMw.C b/16/ID_MMw.C
deleted file mode 100755 (executable)
index 8d44c05..0000000
+++ /dev/null
@@ -1,953 +0,0 @@
-// NEWMM.C\r
-\r
-/*\r
-=============================================================================\r
-\r
-                  ID software memory manager\r
-                  --------------------------\r
-\r
-Primary coder: John Carmack\r
-\r
-RELIES ON\r
----------\r
-Quit (char *error) function\r
-\r
-\r
-WORK TO DO\r
-----------\r
-MM_SizePtr to change the size of a given pointer\r
-\r
-Multiple purge levels utilized\r
-\r
-EMS / XMS unmanaged routines\r
-\r
-=============================================================================\r
-*/\r
-\r
-#include "ID_HEADS.H"\r
-#pragma hdrstop\r
-\r
-#pragma warn -pro\r
-#pragma warn -use\r
-\r
-/*\r
-=============================================================================\r
-\r
-                                                       LOCAL INFO\r
-\r
-=============================================================================\r
-*/\r
-\r
-#define LOCKBIT                0x80    // if set in attributes, block cannot be moved\r
-#define PURGEBITS      3               // 0-3 level, 0= unpurgable, 3= purge first\r
-#define PURGEMASK      0xfffc\r
-#define BASEATTRIBUTES 0       // unlocked, non purgable\r
-\r
-#define MAXUMBS                10\r
-\r
-typedef struct mmblockstruct\r
-{\r
-       unsigned        start,length;\r
-       unsigned        attributes;\r
-       memptr          *useptr;        // pointer to the segment start\r
-       struct mmblockstruct far *next;\r
-} mmblocktype;\r
-\r
-\r
-//#define GETNEWBLOCK {if(!(mmnew=mmfree))Quit("MM_GETNEWBLOCK: No free blocks!")\\r
-//     ;mmfree=mmfree->next;}\r
-\r
-#define GETNEWBLOCK {if(!mmfree)MML_ClearBlock();mmnew=mmfree;mmfree=mmfree->next;}\r
-\r
-#define FREEBLOCK(x) {*x->useptr=NULL;x->next=mmfree;mmfree=x;}\r
-\r
-/*\r
-=============================================================================\r
-\r
-                                                GLOBAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-mminfotype     mminfo;\r
-memptr         bufferseg;\r
-boolean                mmerror;\r
-\r
-void           (* beforesort) (void);\r
-void           (* aftersort) (void);\r
-\r
-/*\r
-=============================================================================\r
-\r
-                                                LOCAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-boolean                mmstarted;\r
-\r
-void far       *farheap;\r
-void           *nearheap;\r
-\r
-mmblocktype    far mmblocks[MAXBLOCKS]\r
-                       ,far *mmhead,far *mmfree,far *mmrover,far *mmnew;\r
-\r
-boolean                bombonerror;\r
-\r
-//unsigned     totalEMSpages,freeEMSpages,EMSpageframe,EMSpagesmapped,EMShandle;\r
-\r
-void           (* XMSaddr) (void);             // far pointer to XMS driver\r
-\r
-unsigned       numUMBs,UMBbase[MAXUMBS];\r
-\r
-//==========================================================================\r
-\r
-//\r
-// local prototypes\r
-//\r
-\r
-boolean                MML_CheckForEMS (void);\r
-void           MML_ShutdownEMS (void);\r
-void           MM_MapEMS (void);\r
-boolean        MML_CheckForXMS (void);\r
-void           MML_ShutdownXMS (void);\r
-void           MML_UseSpace (unsigned segstart, unsigned seglength);\r
-void           MML_ClearBlock (void);\r
-\r
-//==========================================================================\r
-\r
-/*\r
-======================\r
-=\r
-= MML_CheckForXMS\r
-=\r
-= Check for XMM driver\r
-=\r
-=======================\r
-*/\r
-\r
-boolean MML_CheckForXMS (void)\r
-{\r
-       numUMBs = 0;\r
-\r
-asm {\r
-       mov     ax,0x4300\r
-       int     0x2f                            // query status of installed diver\r
-       cmp     al,0x80\r
-       je      good\r
-       }\r
-\r
-       return false;\r
-good:\r
-       return true;\r
-}\r
-\r
-\r
-/*\r
-======================\r
-=\r
-= MML_SetupXMS\r
-=\r
-= Try to allocate all upper memory block\r
-=\r
-=======================\r
-*/\r
-\r
-void MML_SetupXMS (void)\r
-{\r
-       unsigned        base,size;\r
-\r
-asm    {\r
-       mov     ax,0x4310\r
-       int     0x2f\r
-       mov     [WORD PTR XMSaddr],bx\r
-       mov     [WORD PTR XMSaddr+2],es         // function pointer to XMS driver\r
-       }\r
-\r
-getmemory:\r
-asm    {\r
-       mov     ah,XMS_ALLOCUMB\r
-       mov     dx,0xffff                                       // try for largest block possible\r
-       call    [DWORD PTR XMSaddr]\r
-       or      ax,ax\r
-       jnz     gotone\r
-\r
-       cmp     bl,0xb0                                         // error: smaller UMB is available\r
-       jne     done;\r
-\r
-       mov     ah,XMS_ALLOCUMB\r
-       call    [DWORD PTR XMSaddr]             // DX holds largest available UMB\r
-       or      ax,ax\r
-       jz      done                                            // another error...\r
-       }\r
-\r
-gotone:\r
-asm    {\r
-       mov     [base],bx\r
-       mov     [size],dx\r
-       }\r
-       MML_UseSpace (base,size);\r
-       mminfo.XMSmem += size*16;\r
-       UMBbase[numUMBs] = base;\r
-       numUMBs++;\r
-       if (numUMBs < MAXUMBS)\r
-               goto getmemory;\r
-\r
-done:;\r
-}\r
-\r
-\r
-/*\r
-======================\r
-=\r
-= MML_ShutdownXMS\r
-=\r
-======================\r
-*/\r
-\r
-void MML_ShutdownXMS (void)\r
-{\r
-       int     i;\r
-       unsigned        base;\r
-\r
-       for (i=0;i<numUMBs;i++)\r
-       {\r
-               base = UMBbase[i];\r
-\r
-asm    mov     ah,XMS_FREEUMB\r
-asm    mov     dx,[base]\r
-asm    call    [DWORD PTR XMSaddr]\r
-       }\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-======================\r
-=\r
-= MML_UseSpace\r
-=\r
-= Marks a range of paragraphs as usable by the memory manager\r
-= This is used to mark space for the near heap, far heap, ems page frame,\r
-= and upper memory blocks\r
-=\r
-======================\r
-*/\r
-\r
-void MML_UseSpace (unsigned segstart, unsigned seglength)\r
-{\r
-       mmblocktype far *scan,far *last;\r
-       unsigned        oldend;\r
-       long            extra;\r
-\r
-       scan = last = mmhead;\r
-       mmrover = mmhead;               // reset rover to start of memory\r
-\r
-//\r
-// search for the block that contains the range of segments\r
-//\r
-       while (scan->start+scan->length < segstart)\r
-       {\r
-               last = scan;\r
-               scan = scan->next;\r
-       }\r
-\r
-//\r
-// take the given range out of the block\r
-//\r
-       oldend = scan->start + scan->length;\r
-       extra = oldend - (segstart+seglength);\r
-       if (extra < 0)\r
-               Quit ("MML_UseSpace: Segment spans two blocks!");\r
-\r
-       if (segstart == scan->start)\r
-       {\r
-               last->next = scan->next;                        // unlink block\r
-               FREEBLOCK(scan);\r
-               scan = last;\r
-       }\r
-       else\r
-               scan->length = segstart-scan->start;    // shorten block\r
-\r
-       if (extra > 0)\r
-       {\r
-               GETNEWBLOCK;\r
-               mmnew->useptr = NULL;\r
-\r
-               mmnew->next = scan->next;\r
-               scan->next = mmnew;\r
-               mmnew->start = segstart+seglength;\r
-               mmnew->length = extra;\r
-               mmnew->attributes = LOCKBIT;\r
-       }\r
-\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-====================\r
-=\r
-= MML_ClearBlock\r
-=\r
-= We are out of blocks, so free a purgable block\r
-=\r
-====================\r
-*/\r
-\r
-void MML_ClearBlock (void)\r
-{\r
-       mmblocktype far *scan,far *last;\r
-\r
-       scan = mmhead->next;\r
-\r
-       while (scan)\r
-       {\r
-               if (!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS) )\r
-               {\r
-                       MM_FreePtr(scan->useptr);\r
-                       return;\r
-               }\r
-               scan = scan->next;\r
-       }\r
-\r
-       Quit ("MM_ClearBlock: No purgable blocks!");\r
-}\r
-\r
-\r
-//==========================================================================\r
-\r
-/*\r
-===================\r
-=\r
-= MM_Startup\r
-=\r
-= Grabs all space from turbo with malloc/farmalloc\r
-= Allocates bufferseg misc buffer\r
-=\r
-===================\r
-*/\r
-\r
-static char *ParmStrings[] = {"noems","noxms",""};\r
-\r
-void MM_Startup (void)\r
-{\r
-       int i;\r
-       unsigned        long length;\r
-       void far        *start;\r
-       unsigned        segstart,seglength,endfree;\r
-\r
-       if (mmstarted)\r
-               MM_Shutdown ();\r
-\r
-\r
-       mmstarted = true;\r
-       bombonerror = true;\r
-//\r
-// set up the linked list (everything in the free list;\r
-//\r
-       mmhead = NULL;\r
-       mmfree = &mmblocks[0];\r
-       for (i=0;i<MAXBLOCKS-1;i++)\r
-               mmblocks[i].next = &mmblocks[i+1];\r
-       mmblocks[i].next = NULL;\r
-\r
-//\r
-// locked block of all memory until we punch out free space\r
-//\r
-       GETNEWBLOCK;\r
-       mmhead = mmnew;                         // this will allways be the first node\r
-       mmnew->start = 0;\r
-       mmnew->length = 0xffff;\r
-       mmnew->attributes = LOCKBIT;\r
-       mmnew->next = NULL;\r
-       mmrover = mmhead;\r
-\r
-\r
-//\r
-// get all available near conventional memory segments\r
-//\r
-       length=coreleft();\r
-       start = (void far *)(nearheap = malloc(length));\r
-\r
-       length -= 16-(FP_OFF(start)&15);\r
-       length -= SAVENEARHEAP;\r
-       seglength = length / 16;                        // now in paragraphs\r
-       segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
-       MML_UseSpace (segstart,seglength);\r
-       mminfo.nearheap = length;\r
-\r
-//\r
-// get all available far conventional memory segments\r
-//\r
-       length=farcoreleft();\r
-       start = farheap = farmalloc(length);\r
-       length -= 16-(FP_OFF(start)&15);\r
-       length -= SAVEFARHEAP;\r
-       seglength = length / 16;                        // now in paragraphs\r
-       segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
-       MML_UseSpace (segstart,seglength);\r
-       mminfo.farheap = length;\r
-       mminfo.mainmem = mminfo.nearheap + mminfo.farheap;\r
-\r
-//\r
-// allocate the misc buffer\r
-//\r
-       mmrover = mmhead;               // start looking for space after low block\r
-\r
-       MM_GetPtr (&bufferseg,BUFFERSIZE);\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-====================\r
-=\r
-= MM_Shutdown\r
-=\r
-= Frees all conventional, EMS, and XMS allocated\r
-=\r
-====================\r
-*/\r
-\r
-void MM_Shutdown (void)\r
-{\r
-  if (!mmstarted)\r
-       return;\r
-\r
-  farfree (farheap);\r
-  free (nearheap);\r
-//  MML_ShutdownXMS ();\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-====================\r
-=\r
-= MM_GetPtr\r
-=\r
-= Allocates an unlocked, unpurgable block\r
-=\r
-====================\r
-*/\r
-\r
-void MM_GetPtr (memptr *baseptr,unsigned long size)\r
-{\r
-       mmblocktype far *scan,far *lastscan,far *endscan\r
-                               ,far *purge,far *next;\r
-       int                     search;\r
-       unsigned        needed,startseg;\r
-\r
-       needed = (size+15)/16;          // convert size from bytes to paragraphs\r
-\r
-       GETNEWBLOCK;                            // fill in start and next after a spot is found\r
-       mmnew->length = needed;\r
-       mmnew->useptr = baseptr;\r
-       mmnew->attributes = BASEATTRIBUTES;\r
-\r
-tryagain:\r
-       for (search = 0; search<3; search++)\r
-       {\r
-       //\r
-       // first search:        try to allocate right after the rover, then on up\r
-       // second search:       search from the head pointer up to the rover\r
-       // third search:        compress memory, then scan from start\r
-               if (search == 1 && mmrover == mmhead)\r
-                       search++;\r
-\r
-               switch (search)\r
-               {\r
-               case 0:\r
-                       lastscan = mmrover;\r
-                       scan = mmrover->next;\r
-                       endscan = NULL;\r
-                       break;\r
-               case 1:\r
-                       lastscan = mmhead;\r
-                       scan = mmhead->next;\r
-                       endscan = mmrover;\r
-                       break;\r
-               case 2:\r
-                       MM_SortMem ();\r
-                       lastscan = mmhead;\r
-                       scan = mmhead->next;\r
-                       endscan = NULL;\r
-                       break;\r
-               }\r
-\r
-               startseg = lastscan->start + lastscan->length;\r
-\r
-               while (scan != endscan)\r
-               {\r
-                       if (scan->start - startseg >= needed)\r
-                       {\r
-                       //\r
-                       // got enough space between the end of lastscan and\r
-                       // the start of scan, so throw out anything in the middle\r
-                       // and allocate the new block\r
-                       //\r
-                               purge = lastscan->next;\r
-                               lastscan->next = mmnew;\r
-                               mmnew->start = *(unsigned *)baseptr = startseg;\r
-                               mmnew->next = scan;\r
-                               while ( purge != scan)\r
-                               {       // free the purgable block\r
-                                       next = purge->next;\r
-                                       FREEBLOCK(purge);\r
-                                       purge = next;           // purge another if not at scan\r
-                               }\r
-                               mmrover = mmnew;\r
-                               return; // good allocation!\r
-                       }\r
-\r
-                       //\r
-                       // if this block is purge level zero or locked, skip past it\r
-                       //\r
-                       if ( (scan->attributes & LOCKBIT)\r
-                               || !(scan->attributes & PURGEBITS) )\r
-                       {\r
-                               lastscan = scan;\r
-                               startseg = lastscan->start + lastscan->length;\r
-                       }\r
-\r
-\r
-                       scan=scan->next;                // look at next line\r
-               }\r
-       }\r
-\r
-       if (bombonerror)\r
-       {\r
-\r
-extern char configname[];\r
-extern boolean insetupscaling;\r
-extern int     viewsize;\r
-boolean SetViewSize (unsigned width, unsigned height);\r
-#define HEIGHTRATIO            0.50\r
-//\r
-// wolf hack -- size the view down\r
-//\r
-               if (!insetupscaling && viewsize>10)\r
-               {\r
-mmblocktype    far *savedmmnew;\r
-                       savedmmnew = mmnew;\r
-                       viewsize -= 2;\r
-                       SetViewSize (viewsize*16,viewsize*16*HEIGHTRATIO);\r
-                       mmnew = savedmmnew;\r
-                       goto tryagain;\r
-               }\r
-\r
-//             unlink(configname);\r
-               Quit ("MM_GetPtr: Out of memory!");\r
-       }\r
-       else\r
-               mmerror = true;\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-====================\r
-=\r
-= MM_FreePtr\r
-=\r
-= Deallocates an unlocked, purgable block\r
-=\r
-====================\r
-*/\r
-\r
-void MM_FreePtr (memptr *baseptr)\r
-{\r
-       mmblocktype far *scan,far *last;\r
-\r
-       last = mmhead;\r
-       scan = last->next;\r
-\r
-       if (baseptr == mmrover->useptr) // removed the last allocated block\r
-               mmrover = mmhead;\r
-\r
-       while (scan->useptr != baseptr && scan)\r
-       {\r
-               last = scan;\r
-               scan = scan->next;\r
-       }\r
-\r
-       if (!scan)\r
-               Quit ("MM_FreePtr: Block not found!");\r
-\r
-       last->next = scan->next;\r
-\r
-       FREEBLOCK(scan);\r
-}\r
-//==========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= MM_SetPurge\r
-=\r
-= Sets the purge level for a block (locked blocks cannot be made purgable)\r
-=\r
-=====================\r
-*/\r
-\r
-void MM_SetPurge (memptr *baseptr, int purge)\r
-{\r
-       mmblocktype far *start;\r
-\r
-       start = mmrover;\r
-\r
-       do\r
-       {\r
-               if (mmrover->useptr == baseptr)\r
-                       break;\r
-\r
-               mmrover = mmrover->next;\r
-\r
-               if (!mmrover)\r
-                       mmrover = mmhead;\r
-               else if (mmrover == start)\r
-                       Quit ("MM_SetPurge: Block not found!");\r
-\r
-       } while (1);\r
-\r
-       mmrover->attributes &= ~PURGEBITS;\r
-       mmrover->attributes |= purge;\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= MM_SetLock\r
-=\r
-= Locks / unlocks the block\r
-=\r
-=====================\r
-*/\r
-\r
-void MM_SetLock (memptr *baseptr, boolean locked)\r
-{\r
-       mmblocktype far *start;\r
-\r
-       start = mmrover;\r
-\r
-       do\r
-       {\r
-               if (mmrover->useptr == baseptr)\r
-                       break;\r
-\r
-               mmrover = mmrover->next;\r
-\r
-               if (!mmrover)\r
-                       mmrover = mmhead;\r
-               else if (mmrover == start)\r
-                       Quit ("MM_SetLock: Block not found!");\r
-\r
-       } while (1);\r
-\r
-       mmrover->attributes &= ~LOCKBIT;\r
-       mmrover->attributes |= locked*LOCKBIT;\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= MM_SortMem\r
-=\r
-= Throws out all purgable stuff and compresses movable blocks\r
-=\r
-=====================\r
-*/\r
-\r
-void MM_SortMem (void)\r
-{\r
-       mmblocktype far *scan,far *last,far *next;\r
-       unsigned        start,length,source,dest;\r
-       int                     playing;\r
-\r
-       //\r
-       // lock down a currently playing sound\r
-       //\r
-       playing = SD_SoundPlaying ();\r
-       if (playing)\r
-       {\r
-               switch (SoundMode)\r
-               {\r
-               case sdm_PC:\r
-                       playing += STARTPCSOUNDS;\r
-                       break;\r
-               case sdm_AdLib:\r
-                       playing += STARTADLIBSOUNDS;\r
-                       break;\r
-               }\r
-               MM_SetLock(&(memptr)audiosegs[playing],true);\r
-       }\r
-\r
-\r
-       SD_StopSound();\r
-\r
-       if (beforesort)\r
-               beforesort();\r
-\r
-       scan = mmhead;\r
-\r
-       last = NULL;            // shut up compiler warning\r
-\r
-       while (scan)\r
-       {\r
-               if (scan->attributes & LOCKBIT)\r
-               {\r
-               //\r
-               // block is locked, so try to pile later blocks right after it\r
-               //\r
-                       start = scan->start + scan->length;\r
-               }\r
-               else\r
-               {\r
-                       if (scan->attributes & PURGEBITS)\r
-                       {\r
-                       //\r
-                       // throw out the purgable block\r
-                       //\r
-                               next = scan->next;\r
-                               FREEBLOCK(scan);\r
-                               last->next = next;\r
-                               scan = next;\r
-                               continue;\r
-                       }\r
-                       else\r
-                       {\r
-                       //\r
-                       // push the non purgable block on top of the last moved block\r
-                       //\r
-                               if (scan->start != start)\r
-                               {\r
-                                       length = scan->length;\r
-                                       source = scan->start;\r
-                                       dest = start;\r
-                                       while (length > 0xf00)\r
-                                       {\r
-                                               movedata(source,0,dest,0,0xf00*16);\r
-                                               length -= 0xf00;\r
-                                               source += 0xf00;\r
-                                               dest += 0xf00;\r
-                                       }\r
-                                       movedata(source,0,dest,0,length*16);\r
-\r
-                                       scan->start = start;\r
-                                       *(unsigned *)scan->useptr = start;\r
-                               }\r
-                               start = scan->start + scan->length;\r
-                       }\r
-               }\r
-\r
-               last = scan;\r
-               scan = scan->next;              // go to next block\r
-       }\r
-\r
-       mmrover = mmhead;\r
-\r
-       if (aftersort)\r
-               aftersort();\r
-\r
-       if (playing)\r
-               MM_SetLock(&(memptr)audiosegs[playing],false);\r
-}\r
-\r
-\r
-//==========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= MM_ShowMemory\r
-=\r
-=====================\r
-*/\r
-\r
-void MM_ShowMemory (void)\r
-{\r
-       mmblocktype far *scan;\r
-       unsigned color,temp,x,y;\r
-       long    end,owner;\r
-       char    scratch[80],str[10];\r
-\r
-       temp = bufferofs;\r
-       bufferofs = displayofs;\r
-       scan = mmhead;\r
-\r
-       end = -1;\r
-\r
-       while (scan)\r
-       {\r
-               if (scan->attributes & PURGEBITS)\r
-                       color = 5;              // dark purple = purgable\r
-               else\r
-                       color = 9;              // medium blue = non purgable\r
-               if (scan->attributes & LOCKBIT)\r
-                       color = 12;             // red = locked\r
-               if (scan->start<=end)\r
-                       Quit ("MM_ShowMemory: Memory block order currupted!");\r
-               end = scan->length-1;\r
-               y = scan->start/320;\r
-               x = scan->start%320;\r
-               VW_Hlin(x,x+end,y,color);\r
-               VW_Plot(x,y,15);\r
-               if (scan->next && scan->next->start > end+1)\r
-                       VW_Hlin(x+end+1,x+(scan->next->start-scan->start),y,0); // black = free\r
-\r
-               scan = scan->next;\r
-       }\r
-\r
-       VW_FadeIn ();\r
-       IN_Ack();\r
-\r
-       bufferofs = temp;\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= MM_DumpData\r
-=\r
-=====================\r
-*/\r
-\r
-void MM_DumpData (void)\r
-{\r
-       mmblocktype far *scan,far *best;\r
-       long    lowest,oldlowest;\r
-       unsigned        owner;\r
-       char    lock,purge;\r
-       FILE    *dumpfile;\r
-\r
-\r
-       free (nearheap);\r
-       dumpfile = fopen ("MMDUMP.TXT","w");\r
-       if (!dumpfile)\r
-               Quit ("MM_DumpData: Couldn't open MMDUMP.TXT!");\r
-\r
-       lowest = -1;\r
-       do\r
-       {\r
-               oldlowest = lowest;\r
-               lowest = 0xffff;\r
-\r
-               scan = mmhead;\r
-               while (scan)\r
-               {\r
-                       owner = (unsigned)scan->useptr;\r
-\r
-                       if (owner && owner<lowest && owner > oldlowest)\r
-                       {\r
-                               best = scan;\r
-                               lowest = owner;\r
-                       }\r
-\r
-                       scan = scan->next;\r
-               }\r
-\r
-               if (lowest != 0xffff)\r
-               {\r
-                       if (best->attributes & PURGEBITS)\r
-                               purge = 'P';\r
-                       else\r
-                               purge = '-';\r
-                       if (best->attributes & LOCKBIT)\r
-                               lock = 'L';\r
-                       else\r
-                               lock = '-';\r
-                       fprintf (dumpfile,"0x%p (%c%c) = %u\n"\r
-                       ,(unsigned)lowest,lock,purge,best->length);\r
-               }\r
-\r
-       } while (lowest != 0xffff);\r
-\r
-       fclose (dumpfile);\r
-       Quit ("MMDUMP.TXT created.");\r
-}\r
-\r
-//==========================================================================\r
-\r
-\r
-/*\r
-======================\r
-=\r
-= MM_UnusedMemory\r
-=\r
-= Returns the total free space without purging\r
-=\r
-======================\r
-*/\r
-\r
-long MM_UnusedMemory (void)\r
-{\r
-       unsigned free;\r
-       mmblocktype far *scan;\r
-\r
-       free = 0;\r
-       scan = mmhead;\r
-\r
-       while (scan->next)\r
-       {\r
-               free += scan->next->start - (scan->start + scan->length);\r
-               scan = scan->next;\r
-       }\r
-\r
-       return free*16l;\r
-}\r
-\r
-//==========================================================================\r
-\r
-\r
-/*\r
-======================\r
-=\r
-= MM_TotalFree\r
-=\r
-= Returns the total free space with purging\r
-=\r
-======================\r
-*/\r
-\r
-long MM_TotalFree (void)\r
-{\r
-       unsigned free;\r
-       mmblocktype far *scan;\r
-\r
-       free = 0;\r
-       scan = mmhead;\r
-\r
-       while (scan->next)\r
-       {\r
-               if ((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))\r
-                       free += scan->length;\r
-               free += scan->next->start - (scan->start + scan->length);\r
-               scan = scan->next;\r
-       }\r
-\r
-       return free*16l;\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= MM_BombOnError\r
-=\r
-=====================\r
-*/\r
-\r
-void MM_BombOnError (boolean bomb)\r
-{\r
-       bombonerror = bomb;\r
-}\r
-\r
-\r