]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_mm.c
major changes~ ^^ it works~
[16.git] / src / lib / 16_mm.c
1 /* Catacomb Armageddon Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // NEWMM.C\r
20 \r
21 /*\r
22 =============================================================================\r
23 \r
24                         ID software memory manager\r
25                         --------------------------\r
26 \r
27 Primary coder: John Carmack\r
28 \r
29 RELIES ON\r
30 ---------\r
31 Quit (char *error) function\r
32 \r
33 \r
34 WORK TO DO\r
35 ----------\r
36 MM_SizePtr to change the size of a given pointer\r
37 \r
38 Multiple purge levels utilized\r
39 \r
40 EMS / XMS unmanaged routines\r
41 \r
42 =============================================================================\r
43 */\r
44 \r
45 #include "src/lib/16_mm.h"\r
46 \r
47 /*\r
48 ======================\r
49 =\r
50 = MML_CheckForEMS\r
51 =\r
52 = Routine from p36 of Extending DOS\r
53 =\r
54 =======================\r
55 */\r
56 \r
57 boolean MML_CheckForEMS (void)\r
58 {\r
59         boolean emmcfems;\r
60         char    emmname[] = "EMMXXXX0";\r
61 //              mov     dx,OFFSET emmname\r
62         __asm {\r
63                 LEA     DX, emmname     //fix by andrius4669\r
64                 mov     ax,0x3d00\r
65                 int     0x21            // try to open EMMXXXX0 device\r
66                 jc      error\r
67 \r
68                 mov     bx,ax\r
69                 mov     ax,0x4400\r
70 \r
71                 int     0x21            // get device info\r
72                 jc      error\r
73 \r
74                 and     dx,0x80\r
75                 jz      error\r
76 \r
77                 mov     ax,0x4407\r
78 \r
79                 int     0x21            // get status\r
80                 jc      error\r
81                 or      al,al\r
82                 jz      error\r
83 \r
84                 mov     ah,0x3e\r
85                 int     0x21            // close handle\r
86                 jc      error\r
87                 //\r
88                 // EMS is good\r
89                 //\r
90                 mov     emmcfems,1\r
91                 jmp End\r
92                 error:\r
93                 //\r
94                 // EMS is bad\r
95                 //\r
96                 mov     emmcfems,0\r
97                 End:\r
98         }\r
99         return(emmcfems);\r
100 }\r
101 \r
102 \r
103 /*\r
104 ======================\r
105 =\r
106 = MML_SetupEMS\r
107 =\r
108 =======================\r
109 */\r
110 \r
111 void MML_SetupEMS (void)\r
112 {\r
113         char    str[80],str2[10];\r
114         unsigned        err;\r
115         boolean errorflag=false;\r
116         union REGS CPURegs;\r
117 \r
118         EMSVer = 0;\r
119         totalEMSpages = freeEMSpages = EMSpageframe = EMSpagesmapped = 0;\r
120 \r
121         __asm\r
122                 {\r
123                 mov     ah,EMS_STATUS\r
124                 int     EMS_INT                                         // make sure EMS hardware is present\r
125                 or      ah,ah\r
126                 jnz     error\r
127 \r
128                 mov     ah,EMS_VERSION\r
129                 int     EMS_INT\r
130                 or      ah,ah\r
131                 jnz     error\r
132                 mov     [EMSVer],ax                             //      set EMSVer\r
133                 cmp     al,0x32                                         // only work on ems 3.2 or greater\r
134                 jb      error\r
135 \r
136                 mov     ah,EMS_GETFRAME\r
137                 int     EMS_INT                                         // find the page frame address\r
138                 or      ah,ah\r
139                 jnz     error\r
140                 mov     [EMSpageframe],bx\r
141 \r
142                 mov     ah,EMS_GETPAGES\r
143                 int     EMS_INT                                         // find out how much EMS is there\r
144                 or      ah,ah\r
145                 jnz     error\r
146                 mov     [totalEMSpages],dx\r
147                 mov     [freeEMSpages],bx\r
148                 or      bx,bx\r
149                 jz      noEMS                                           // no EMS at all to allocate\r
150 \r
151                 cmp     bx,4\r
152                 jle     getpages                                        // there is only 1,2,3,or 4 pages\r
153                 mov     bx,4                                            // we can't use more than 4 pages\r
154 \r
155 getpages:\r
156                 mov     [EMSpagesmapped],bx\r
157                 mov     ah,EMS_ALLOCPAGES                       // allocate up to 64k of EMS\r
158                 int     EMS_INT\r
159                 or      ah,ah\r
160                 jnz     error\r
161                 mov     [EMShandle],dx\r
162                 jmp End\r
163 error:\r
164                 mov     errorflag,1\r
165                 jmp End\r
166 noEMS:\r
167 End:\r
168         }\r
169         if(errorflag==true)\r
170         {\r
171                 err = CPURegs.h.ah;\r
172                 strcpy(str,"MML_SetupEMS: EMS error 0x");\r
173                 itoa(err,str2,16);\r
174                 strcpy(str,str2);\r
175                 printf("%s\n",str);\r
176         }\r
177 }\r
178 \r
179 \r
180 /*\r
181 ======================\r
182 =\r
183 = MML_ShutdownEMS\r
184 =\r
185 =======================\r
186 */\r
187 \r
188 void MML_ShutdownEMS (void)\r
189 {\r
190         boolean errorflag=false;\r
191         if (!EMShandle)\r
192                 return;\r
193         __asm\r
194         {\r
195                 mov     ah,EMS_FREEPAGES\r
196                 mov     dx,[EMShandle]\r
197                 int     EMS_INT\r
198                 or      ah,ah\r
199                 jz      ok\r
200                 mov     errorflag,1\r
201                 ok:\r
202         }\r
203         if(errorflag==true) printf("MML_ShutdownEMS: Error freeing EMS!");      //++++ add something\r
204 }\r
205 \r
206 /*\r
207 ====================\r
208 =\r
209 = MM_MapEMS\r
210 =\r
211 = Maps the 64k of EMS used by memory manager into the page frame\r
212 = for general use.  This only needs to be called if you are keeping\r
213 = other things in EMS.\r
214 =\r
215 ====================\r
216 */\r
217 \r
218 void MM_MapEMS (void)\r
219 {\r
220         char    str[80],str2[10];\r
221         unsigned        err;\r
222         boolean errorflag=false;\r
223         int     i;\r
224         union REGS CPURegs;\r
225 \r
226         for (i=0;i<EMSpagesmapped;i++)\r
227         {\r
228                 __asm\r
229                 {\r
230                         mov     ah,EMS_MAPPAGE\r
231                         mov     bx,[i]                  // logical page\r
232                         mov     al,bl                   // physical page\r
233                         mov     dx,[EMShandle]  // handle\r
234                         int     EMS_INT\r
235                         or      ah,ah\r
236                         jnz     error\r
237                         jmp End\r
238                         error:\r
239                         mov     errorflag,1\r
240                         End:\r
241                 }\r
242                 if(errorflag==true)\r
243                 {\r
244                         err = CPURegs.h.ah;\r
245                         strcpy(str,"MM_MapEMS: EMS error 0x");\r
246                         itoa(err,str2,16);\r
247                         strcpy(str,str2);\r
248                         printf("%s\n",str);\r
249                 }\r
250         }\r
251         return;\r
252 }\r
253 \r
254 //==========================================================================\r
255 \r
256 /*\r
257 ======================\r
258 =\r
259 = MML_CheckForXMS\r
260 =\r
261 = Check for XMM driver\r
262 =\r
263 =======================\r
264 */\r
265 \r
266 boolean MML_CheckForXMS (void)\r
267 {\r
268         boolean errorflag=false;\r
269         numUMBs = 0;\r
270 \r
271         __asm\r
272         {\r
273                 mov     ax,0x4300\r
274                 int     0x2f                            // query status of installed diver\r
275                 cmp     al,0x80\r
276                 je      good\r
277                 mov     errorflag,1\r
278                 good:\r
279         }\r
280         if(errorflag==true) return false;\r
281         else return true;\r
282 }\r
283 \r
284 \r
285 /*\r
286 ======================\r
287 =\r
288 = MML_SetupXMS\r
289 =\r
290 = Try to allocate all upper memory block\r
291 =\r
292 =======================\r
293 */\r
294 \r
295 void MML_SetupXMS (void)\r
296 {\r
297         unsigned        base,size;\r
298 \r
299         __asm\r
300         {\r
301                 mov     ax,0x4310\r
302                 int     0x2f\r
303                 mov     [WORD PTR XMSaddr],bx\r
304                 mov     [WORD PTR XMSaddr+2],es         // function pointer to XMS driver\r
305         }\r
306 getmemory:\r
307         __asm\r
308         {\r
309                 mov     ah,XMS_ALLOCUMB\r
310                 mov     dx,0xffff                                       // try for largest block possible\r
311                 call    [DWORD PTR XMSaddr]\r
312                 or      ax,ax\r
313                 jnz     gotone\r
314 \r
315                 cmp     bl,0xb0                                         // error: smaller UMB is available\r
316                 jne     done;\r
317 \r
318                 mov     ah,XMS_ALLOCUMB\r
319                 call    [DWORD PTR XMSaddr]             // DX holds largest available UMB\r
320                 or      ax,ax\r
321                 jz      done                                            // another error...\r
322 \r
323 gotone:\r
324                 mov     [base],bx\r
325                 mov     [size],dx\r
326 done:\r
327         }\r
328         MML_UseSpace (base,size);\r
329         mminfo.XMSmem += size*16;\r
330         UMBbase[numUMBs] = base;\r
331         numUMBs++;\r
332         if (numUMBs < MAXUMBS)\r
333                 goto getmemory;\r
334 }\r
335 \r
336 \r
337 /*\r
338 ======================\r
339 =\r
340 = MML_ShutdownXMS\r
341 =\r
342 ======================\r
343 */\r
344 \r
345 void MML_ShutdownXMS (void)\r
346 {\r
347         int     i;\r
348         unsigned        base;\r
349 \r
350         for (i=0;i<numUMBs;i++)\r
351         {\r
352                 base = UMBbase[i];\r
353                 __asm\r
354                 {\r
355                         mov     ah,XMS_FREEUMB\r
356                         mov     dx,[base]\r
357                         call    [DWORD PTR XMSaddr]\r
358                 }\r
359         }\r
360 }\r
361 \r
362 //==========================================================================\r
363 \r
364 /*\r
365 ======================\r
366 =\r
367 = MML_UseSpace\r
368 =\r
369 = Marks a range of paragraphs as usable by the memory manager\r
370 = This is used to mark space for the near heap, far heap, ems page frame,\r
371 = and upper memory blocks\r
372 =\r
373 ======================\r
374 */\r
375 \r
376 void MML_UseSpace (unsigned segstart, unsigned seglength)\r
377 {\r
378         mmblocktype far *scan,far *last;\r
379         unsigned        oldend;\r
380         long            extra;\r
381 \r
382         scan = last = mmhead;\r
383         mmrover = mmhead;               // reset rover to start of memory\r
384 \r
385 //\r
386 // search for the block that contains the range of segments\r
387 //\r
388         while (scan->start+scan->length < segstart)\r
389         {\r
390                 last = scan;\r
391                 scan = scan->next;\r
392         }\r
393 \r
394 //\r
395 // take the given range out of the block\r
396 //\r
397         oldend = scan->start + scan->length;\r
398         extra = oldend - (segstart+seglength);\r
399         if (extra < 0)\r
400         {\r
401                 printf("MML_UseSpace: Segment spans two blocks!");\r
402                 return;\r
403         }\r
404 \r
405 \r
406         if (segstart == scan->start)\r
407         {\r
408                 last->next = scan->next;                        // unlink block\r
409                 FREEBLOCK(scan);\r
410                 scan = last;\r
411         }\r
412         else\r
413                 scan->length = segstart-scan->start;    // shorten block\r
414 \r
415         if (extra > 0)\r
416         {\r
417                 GETNEWBLOCK;\r
418                 mmnew->next = scan->next;\r
419                 scan->next = mmnew;\r
420                 mmnew->start = segstart+seglength;\r
421                 mmnew->length = extra;\r
422                 mmnew->attributes = LOCKBIT;\r
423         }\r
424 \r
425 }\r
426 \r
427 //==========================================================================\r
428 \r
429 /*\r
430 ====================\r
431 =\r
432 = MML_ClearBlock\r
433 =\r
434 = We are out of blocks, so free a purgable block\r
435 =\r
436 ====================\r
437 */\r
438 \r
439 void MML_ClearBlock (void)\r
440 {\r
441         mmblocktype far *scan,far *last;\r
442 \r
443         scan = mmhead->next;\r
444 \r
445         while (scan)\r
446         {\r
447                 if (!(scan->attributes&LOCKBIT) && (scan->attributes&PURGEBITS) )\r
448                 {\r
449                         MM_FreePtr(scan->useptr);\r
450                         return;\r
451                 }\r
452                 scan = scan->next;\r
453         }\r
454 \r
455         printf("MM_ClearBlock: No purgable blocks!");\r
456 }\r
457 \r
458 \r
459 //==========================================================================\r
460 \r
461 /*\r
462 ===================\r
463 =\r
464 = MM_Startup\r
465 =\r
466 = Grabs all space from turbo with malloc/farmalloc\r
467 = Allocates bufferseg misc buffer\r
468 =\r
469 ===================\r
470 */\r
471 \r
472 void MM_Startup (void)\r
473 {\r
474         int i;\r
475         dword length;\r
476         void far        *start;\r
477         unsigned        segstart,seglength,endfree;\r
478 \r
479         if (mminfo.mmstarted)\r
480                 MM_Shutdown ();\r
481 \r
482 \r
483         mminfo.mmstarted = true;\r
484         mminfo.bombonerror = true;\r
485 //\r
486 // set up the linked list (everything in the free list;\r
487 //\r
488         mmhead = NULL;\r
489         mmfree = &mmblocks[0];\r
490         for (i=0;i<MAXBLOCKS-1;i++)\r
491                 mmblocks[i].next = &mmblocks[i+1];\r
492         mmblocks[i].next = NULL;\r
493 \r
494 //\r
495 // locked block of all memory until we punch out free space\r
496 //\r
497         GETNEWBLOCK;\r
498         mmhead = mmnew;                         // this will allways be the first node\r
499         mmnew->start = 0;\r
500         mmnew->length = 0xffff;\r
501         mmnew->attributes = LOCKBIT;\r
502         mmnew->next = NULL;\r
503         mmrover = mmhead;\r
504 \r
505 \r
506 //\r
507 // get all available near conventional memory segments\r
508 //\r
509 //----  length=coreleft();\r
510         _nheapgrow();\r
511         length=_memavl();\r
512         start = (void far *)(nearheap = malloc(length));\r
513 \r
514         length -= 16-(FP_OFF(start)&15);\r
515         length -= SAVENEARHEAP;\r
516         seglength = length / 16;                        // now in paragraphs\r
517         segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
518         MML_UseSpace (segstart,seglength);\r
519         mminfo.nearheap = length;\r
520 \r
521 //\r
522 // get all available far conventional memory segments\r
523 //\r
524 //----  length=farcoreleft();\r
525         _fheapgrow();\r
526         length=_memavl();\r
527         start = farheap = _fmalloc(length);\r
528         length -= 16-(FP_OFF(start)&15);\r
529         length -= SAVEFARHEAP;\r
530         seglength = length / 16;                        // now in paragraphs\r
531         segstart = FP_SEG(start)+(FP_OFF(start)+15)/16;\r
532         MML_UseSpace (segstart,seglength);\r
533         mminfo.farheap = length;\r
534         mminfo.mainmem = mminfo.nearheap + mminfo.farheap;\r
535 \r
536 \r
537 //\r
538 // detect EMS and allocate up to 64K at page frame\r
539 //\r
540         mminfo.EMSmem = 0;\r
541         for (i = 1;i < __argc;i++)\r
542         {\r
543                 if ( US_CheckParm(__argv[i],ParmStringsexmm) == 0)\r
544                         goto emsskip;                           // param NOEMS\r
545         }\r
546 \r
547         if (MML_CheckForEMS())\r
548         {\r
549                 //printf("EMS1\n");\r
550                 MML_SetupEMS();                                 // allocate space\r
551                 //printf("EMS2\n");\r
552                 MML_UseSpace (EMSpageframe,EMSpagesmapped*0x400);\r
553                 //printf("EMS3\n");\r
554                 MM_MapEMS();                                    // map in used pages\r
555                 //printf("EMS4\n");\r
556                 mminfo.EMSmem = EMSpagesmapped*0x4000l;\r
557         }\r
558 \r
559 //\r
560 // detect XMS and get upper memory blocks\r
561 //\r
562 emsskip:\r
563         mminfo.XMSmem = 0;\r
564         for (i = 1;i < __argc;i++)\r
565         {\r
566                 if ( US_CheckParm(__argv[i],ParmStringsexmm) == 0)\r
567                         goto xmsskip;                           // param NOXMS\r
568         }\r
569 \r
570         if (MML_CheckForXMS())\r
571         {\r
572 //              printf("XMS!\n");\r
573                 MML_SetupXMS();                                 // allocate as many UMBs as possible\r
574         }\r
575 \r
576 //\r
577 // allocate the misc buffer\r
578 //\r
579 xmsskip:\r
580         mmrover = mmhead;               // start looking for space after low block\r
581 \r
582         MM_GetPtr (&bufferseg,BUFFERSIZE);\r
583 }\r
584 \r
585 //==========================================================================\r
586 \r
587 /*\r
588 ====================\r
589 =\r
590 = MM_Shutdown\r
591 =\r
592 = Frees all conventional, EMS, and XMS allocated\r
593 =\r
594 ====================\r
595 */\r
596 \r
597 void MM_Shutdown (void)\r
598 {\r
599   if (!mminfo.mmstarted)\r
600         return;\r
601 \r
602   _ffree (farheap);\r
603   free (nearheap);\r
604   hfree(hugeheap);\r
605   MML_ShutdownEMS ();\r
606   MML_ShutdownXMS ();\r
607 }\r
608 \r
609 //==========================================================================\r
610 \r
611 /*\r
612 ====================\r
613 =\r
614 = MM_GetPtr\r
615 =\r
616 = Allocates an unlocked, unpurgable block\r
617 =\r
618 ====================\r
619 */\r
620 \r
621 void MM_GetPtr (memptr *baseptr,dword size)\r
622 {\r
623         mmblocktype far *scan,far *lastscan,far *endscan\r
624                                 ,far *purge,far *next;\r
625         int                     search;\r
626         unsigned        needed,startseg;\r
627 \r
628         needed = (size+15)/16;          // convert size from bytes to paragraphs\r
629 \r
630         GETNEWBLOCK;                            // fill in start and next after a spot is found\r
631         mmnew->length = needed;\r
632         mmnew->useptr = baseptr;\r
633         mmnew->attributes = BASEATTRIBUTES;\r
634 \r
635         for (search = 0; search<3; search++)\r
636         {\r
637         //\r
638         // first search:        try to allocate right after the rover, then on up\r
639         // second search:       search from the head pointer up to the rover\r
640         // third search:        compress memory, then scan from start\r
641                 if (search == 1 && mmrover == mmhead)\r
642                         search++;\r
643 \r
644                 switch (search)\r
645                 {\r
646                 case 0:\r
647                         lastscan = mmrover;\r
648                         scan = mmrover->next;\r
649                         endscan = NULL;\r
650                         break;\r
651                 case 1:\r
652                         lastscan = mmhead;\r
653                         scan = mmhead->next;\r
654                         endscan = mmrover;\r
655                         break;\r
656                 case 2:\r
657                         MM_SortMem ();\r
658                         lastscan = mmhead;\r
659                         scan = mmhead->next;\r
660                         endscan = NULL;\r
661                         break;\r
662                 }\r
663 \r
664                 startseg = lastscan->start + lastscan->length;\r
665 \r
666                 while (scan != endscan)\r
667                 {\r
668                         if (scan->start - startseg >= needed)\r
669                         {\r
670                         //\r
671                         // got enough space between the end of lastscan and\r
672                         // the start of scan, so throw out anything in the middle\r
673                         // and allocate the new block\r
674                         //\r
675                                 purge = lastscan->next;\r
676                                 lastscan->next = mmnew;\r
677                                 mmnew->start = *(unsigned *)baseptr = startseg;\r
678                                 mmnew->next = scan;\r
679                                 while ( purge != scan)\r
680                                 {       // free the purgable block\r
681                                         next = purge->next;\r
682                                         FREEBLOCK(purge);\r
683                                         purge = next;           // purge another if not at scan\r
684                                 }\r
685                                 mmrover = mmnew;\r
686                                 return; // good allocation!\r
687                         }\r
688 \r
689                         //\r
690                         // if this block is purge level zero or locked, skip past it\r
691                         //\r
692                         if ( (scan->attributes & LOCKBIT)\r
693                                 || !(scan->attributes & PURGEBITS) )\r
694                         {\r
695                                 lastscan = scan;\r
696                                 startseg = lastscan->start + lastscan->length;\r
697                         }\r
698 \r
699 \r
700                         scan=scan->next;                // look at next line\r
701                 }\r
702         }\r
703 \r
704         if (mminfo.bombonerror)\r
705                 printf(OUT_OF_MEM_MSG,(size-mminfo.nearheap));\r
706         else\r
707                 mminfo.mmerror = true;\r
708 }\r
709 \r
710 //==========================================================================\r
711 \r
712 /*\r
713 ====================\r
714 =\r
715 = MM_FreePtr\r
716 =\r
717 = Allocates an unlocked, unpurgable block\r
718 =\r
719 ====================\r
720 */\r
721 \r
722 void MM_FreePtr (memptr *baseptr)\r
723 {\r
724         mmblocktype far *scan,far *last;\r
725 \r
726         last = mmhead;\r
727         scan = last->next;\r
728 \r
729         if (baseptr == mmrover->useptr) // removed the last allocated block\r
730                 mmrover = mmhead;\r
731 \r
732         while (scan->useptr != baseptr && scan)\r
733         {\r
734                 last = scan;\r
735                 scan = scan->next;\r
736         }\r
737 \r
738         if (!scan)\r
739         {\r
740                 printf("MM_FreePtr: Block not found!");\r
741                 return;\r
742         }\r
743 \r
744         last->next = scan->next;\r
745 \r
746         FREEBLOCK(scan);\r
747 }\r
748 //==========================================================================\r
749 \r
750 /*\r
751 =====================\r
752 =\r
753 = MM_SetPurge\r
754 =\r
755 = Sets the purge level for a block (locked blocks cannot be made purgable)\r
756 =\r
757 =====================\r
758 */\r
759 \r
760 void MM_SetPurge (memptr *baseptr, int purge)\r
761 {\r
762         mmblocktype far *start;\r
763 \r
764         start = mmrover;\r
765 \r
766         do\r
767         {\r
768                 if (mmrover->useptr == baseptr)\r
769                         break;\r
770 \r
771                 mmrover = mmrover->next;\r
772 \r
773                 if (!mmrover)\r
774                         mmrover = mmhead;\r
775                 else if (mmrover == start)\r
776                 {\r
777                         printf("MM_SetPurge: Block not found!");\r
778                         return;\r
779                 }\r
780 \r
781         } while (1);\r
782 \r
783         mmrover->attributes &= ~PURGEBITS;\r
784         mmrover->attributes |= purge;\r
785 }\r
786 \r
787 //==========================================================================\r
788 \r
789 /*\r
790 =====================\r
791 =\r
792 = MM_SetLock\r
793 =\r
794 = Locks / unlocks the block\r
795 =\r
796 =====================\r
797 */\r
798 \r
799 void MM_SetLock (memptr *baseptr, boolean locked)\r
800 {\r
801         mmblocktype far *start;\r
802 \r
803         start = mmrover;\r
804 \r
805         do\r
806         {\r
807                 if (mmrover->useptr == baseptr)\r
808                         break;\r
809 \r
810                 mmrover = mmrover->next;\r
811 \r
812                 if (!mmrover)\r
813                         mmrover = mmhead;\r
814                 else if (mmrover == start)\r
815                 {\r
816                         printf("MM_SetLock: Block not found!");\r
817                         return;\r
818                 }\r
819 \r
820         } while (1);\r
821 \r
822         mmrover->attributes &= ~LOCKBIT;\r
823         mmrover->attributes |= locked*LOCKBIT;\r
824 }\r
825 \r
826 //==========================================================================\r
827 \r
828 /*\r
829 =====================\r
830 =\r
831 = MM_SortMem\r
832 =\r
833 = Throws out all purgable stuff and compresses movable blocks\r
834 =\r
835 =====================\r
836 */\r
837 \r
838 void MM_SortMem (void)\r
839 {\r
840         mmblocktype far *scan,far *last,far *next;\r
841         unsigned        start,length,source,dest,oldborder;\r
842         int                     playing;\r
843 \r
844         //\r
845         // lock down a currently playing sound\r
846         //\r
847 /*++++  playing = SD_SoundPlaying ();\r
848         if (playing)\r
849         {\r
850                 switch (SoundMode)\r
851                 {\r
852                 case sdm_PC:\r
853                         playing += STARTPCSOUNDS;\r
854                         break;\r
855                 case sdm_AdLib:\r
856                         playing += STARTADLIBSOUNDS;\r
857                         break;\r
858                 }\r
859                 MM_SetLock(&(memptr)audiosegs[playing],true);\r
860         }\r
861 \r
862 \r
863         SD_StopSound();*/\r
864 //      oldborder = bordercolor;\r
865 //      VW_ColorBorder (15);\r
866 \r
867         if (beforesort)\r
868                 beforesort();\r
869 \r
870         scan = mmhead;\r
871 \r
872         last = NULL;            // shut up compiler warning\r
873 \r
874         while (scan)\r
875         {\r
876                 if (scan->attributes & LOCKBIT)\r
877                 {\r
878                 //\r
879                 // block is locked, so try to pile later blocks right after it\r
880                 //\r
881                         start = scan->start + scan->length;\r
882                 }\r
883                 else\r
884                 {\r
885                         if (scan->attributes & PURGEBITS)\r
886                         {\r
887                         //\r
888                         // throw out the purgable block\r
889                         //\r
890                                 next = scan->next;\r
891                                 FREEBLOCK(scan);\r
892                                 last->next = next;\r
893                                 scan = next;\r
894                                 continue;\r
895                         }\r
896                         else\r
897                         {\r
898                         //\r
899                         // push the non purgable block on top of the last moved block\r
900                         //\r
901                                 if (scan->start != start)\r
902                                 {\r
903                                         length = scan->length;\r
904                                         source = scan->start;\r
905                                         dest = start;\r
906                                         while (length > 0xf00)\r
907                                         {\r
908                                                 movedata(source,0,dest,0,0xf00*16);\r
909                                                 length -= 0xf00;\r
910                                                 source += 0xf00;\r
911                                                 dest += 0xf00;\r
912                                         }\r
913                                         movedata(source,0,dest,0,length*16);\r
914 \r
915                                         scan->start = start;\r
916                                         *(unsigned *)scan->useptr = start;\r
917                                 }\r
918                                 start = scan->start + scan->length;\r
919                         }\r
920                 }\r
921 \r
922                 last = scan;\r
923                 scan = scan->next;              // go to next block\r
924         }\r
925 \r
926         mmrover = mmhead;\r
927 \r
928         if (aftersort)\r
929                 aftersort();\r
930 \r
931 //      VW_ColorBorder (oldborder);\r
932 \r
933 /*++++  if (playing)\r
934                 MM_SetLock(&(memptr)audiosegs[playing],false);*/\r
935 }\r
936 \r
937 \r
938 //==========================================================================\r
939 \r
940 //****#if 0\r
941 /*\r
942 =====================\r
943 =\r
944 = MM_ShowMemory\r
945 =\r
946 =====================\r
947 */\r
948 \r
949 void MM_ShowMemory (void)\r
950 {\r
951         mmblocktype far *scan;\r
952         unsigned color,temp;//, i;\r
953         long    end,owner;\r
954         char    scratch[80],str[10];\r
955 \r
956 //****  VW_SetDefaultColors();\r
957 //****  VW_SetLineWidth(40);\r
958 //++++mh        temp = bufferofs;\r
959 //++++mh        bufferofs = 0;\r
960 //****  VW_SetScreen (0,0);\r
961 \r
962         scan = mmhead;\r
963 \r
964         end = -1;\r
965 \r
966 //CA_OpenDebug ();\r
967 \r
968         while (scan)\r
969         {\r
970                 if (scan->attributes & PURGEBITS)\r
971                         color = 5;              // dark purple = purgable\r
972                 else\r
973                         color = 9;              // medium blue = non purgable\r
974                 if (scan->attributes & LOCKBIT)\r
975                         color = 12;             // red = locked\r
976                 if (scan->start<=end)\r
977                 {\r
978                         printf("MM_ShowMemory: Memory block order currupted!");\r
979                         return;\r
980                 }\r
981                 end = scan->start+scan->length-1;\r
982 //++++          VW_Hlin(scan->start,(unsigned)end,0,color);\r
983 //++++          VW_Plot(scan->start,0,15);\r
984                 if (scan->next->start > end+1)\r
985 //++++                  VW_Hlin(end+1,scan->next->start,0,0);   // black = free\r
986 \r
987 //****#if 0\r
988 printf("Location:");\r
989 printf("%Fp\t", scan->start);\r
990 strcpy (scratch,"Size:");\r
991 ltoa ((long)scan->length*16,str,10);\r
992 strcat (scratch,str);\r
993 strcat (scratch,"\tOwner:0x");\r
994 owner = (unsigned)scan->useptr;\r
995 ultoa (owner,str,16);\r
996 strcat (scratch,str);\r
997 strcat (scratch,"\n");\r
998 //++++write (debughandle,scratch,strlen(scratch));\r
999 fprintf(stdout, "%s", scratch);\r
1000 //****#endif\r
1001 \r
1002                 scan = scan->next;\r
1003         }\r
1004 \r
1005 //CA_CloseDebug ();\r
1006 \r
1007 //++++mh        IN_Ack();\r
1008 //****  VW_SetLineWidth(64);\r
1009 //++++mh        bufferofs = temp;\r
1010 }\r
1011 //****#endif\r
1012 \r
1013 //==========================================================================\r
1014 \r
1015 \r
1016 /*\r
1017 ======================\r
1018 =\r
1019 = MM_UnusedMemory\r
1020 =\r
1021 = Returns the total free space without purging\r
1022 =\r
1023 ======================\r
1024 */\r
1025 \r
1026 dword MM_UnusedMemory (void)\r
1027 {\r
1028         unsigned free;\r
1029         mmblocktype far *scan;\r
1030 \r
1031         free = 0;\r
1032         scan = mmhead;\r
1033 \r
1034         while (scan->next)\r
1035         {\r
1036                 free += scan->next->start - (scan->start + scan->length);\r
1037                 scan = scan->next;\r
1038         }\r
1039 \r
1040 //      return free*16l;\r
1041         return free;\r
1042 }\r
1043 \r
1044 //==========================================================================\r
1045 \r
1046 \r
1047 /*\r
1048 ======================\r
1049 =\r
1050 = MM_TotalFree\r
1051 =\r
1052 = Returns the total free space with purging\r
1053 =\r
1054 ======================\r
1055 */\r
1056 \r
1057 dword MM_TotalFree (void)\r
1058 {\r
1059         unsigned free;\r
1060         mmblocktype far *scan;\r
1061 \r
1062         free = 0;\r
1063         scan = mmhead;\r
1064 \r
1065         while (scan->next)\r
1066         {\r
1067                 if ((scan->attributes&PURGEBITS) && !(scan->attributes&LOCKBIT))\r
1068                         free += scan->length;\r
1069                 free += scan->next->start - (scan->start + scan->length);\r
1070                 scan = scan->next;\r
1071         }\r
1072 \r
1073 //      return free*16l;\r
1074         return free;\r
1075 }\r
1076 \r
1077 //==========================================================================\r
1078 \r
1079 /*\r
1080 =====================\r
1081 =\r
1082 = MM_Report\r
1083 =\r
1084 =====================\r
1085 */\r
1086 \r
1087 void MM_Report(void)\r
1088 {\r
1089         printf("EMM %x available\n", EMSVer);\r
1090         printf("totalEMSpages=%u\n", totalEMSpages);\r
1091         printf("freeEMSpages=%u\n", freeEMSpages);\r
1092         printf("EMSpageframe=%Fp\n", EMSpageframe);\r
1093         printf("near=%lu\n", mminfo.nearheap);\r
1094         printf("far=%lu\n", mminfo.farheap);\r
1095         printf("EMSmem=%lu\n", mminfo.EMSmem);\r
1096         printf("XMSmem=%lu\n", mminfo.XMSmem);\r
1097         printf("mainmem=%lu\n", mminfo.mainmem);\r
1098         printf("UnusedMemory=%lu\n", MM_UnusedMemory());\r
1099         printf("TotalFree=%lu\n", MM_TotalFree());\r
1100 //      printf("\n");\r
1101 //      printf("UnusedMemory=%lu kb\n", MM_UnusedMemory()/10248);\r
1102 //      printf("TotalFree=%lu kb\n", MM_TotalFree()/10248);\r
1103 }\r
1104 \r
1105 //==========================================================================\r
1106 \r
1107 /*\r
1108 =====================\r
1109 =\r
1110 = MM_EMSVer\r
1111 =\r
1112 =====================\r
1113 \r
1114 \r
1115 int MM_EMSVer(void)\r
1116 {\r
1117         int EMSver;\r
1118         __asm\r
1119         {\r
1120                 mov             ah,EMS_VERSION\r
1121                 int             EMS_INT\r
1122                 mov             EMSver,ax\r
1123         }\r
1124         return(EMSver);\r
1125 }*/\r
1126 \r
1127 //==========================================================================\r
1128 \r
1129 /*\r
1130 =====================\r
1131 =\r
1132 = MM_BombOnError\r
1133 =\r
1134 =====================\r
1135 */\r
1136 \r
1137 void MM_BombOnError (boolean bomb)\r
1138 {\r
1139         mminfo.bombonerror = bomb;\r
1140 }\r
1141 \r
1142 //==========================================================================\r
1143 \r
1144 ///////////////////////////////////////////////////////////////////////////\r
1145 //\r
1146 //      US_CheckParm() - checks to see if a string matches one of a set of\r
1147 //              strings. The check is case insensitive. The routine returns the\r
1148 //              index of the string that matched, or -1 if no matches were found\r
1149 //\r
1150 ///////////////////////////////////////////////////////////////////////////\r
1151 int\r
1152 US_CheckParm(char *parm,char **strings)\r
1153 {\r
1154         char    cp,cs,\r
1155                         *p,*s;\r
1156         int             i;\r
1157 \r
1158         while (!isalpha(*parm)) // Skip non-alphas\r
1159                 parm++;\r
1160 \r
1161         for (i = 0;*strings && **strings;i++)\r
1162         {\r
1163                 for (s = *strings++,p = parm,cs = cp = 0;cs == cp;)\r
1164                 {\r
1165                         cs = *s++;\r
1166                         if (!cs)\r
1167                                 return(i);\r
1168                         cp = *p++;\r
1169 \r
1170                         if (isupper(cs))\r
1171                                 cs = tolower(cs);\r
1172                         if (isupper(cp))\r
1173                                 cp = tolower(cp);\r
1174                 }\r
1175         }\r
1176         return(-1);\r
1177 }\r
1178 \r