home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / MANTSR.ZIP / RELEASE.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1986-02-14  |  6.9 KB  |  194 lines

  1. {**************************************************************************
  2. *   Releases memory above the last MARK call made.                        *
  3. *   Copyright (c) 1986 Kim Kokkonen, TurboPower Software.                 *
  4. *   Released to the public domain for personal, non-commercial use only.  *
  5. ***************************************************************************
  6. *   written 2/8/86                                                        *
  7. ***************************************************************************
  8. *   telephone: 408-378-3672, CompuServe: 72457,2131.                      *
  9. *   requires Turbo version 3 to compile.                                  *
  10. *   Compile with mAx dynamic memory = A000.                               *
  11. ***************************************************************************}
  12.  
  13. {$P128}
  14.  
  15. PROGRAM ReleaseTSR;
  16.   {-release system memory above the last mark call}
  17. CONST
  18.   MaxBlocks = 100;
  19.   Version = '1.0';
  20.   markID = 'MARK PARAMETER BLOCK FOLLOWS'; {marking string for TSR}
  21.   markOffset = $103;          {offset into MARK.COM where markID is found in TSR}
  22.   vectoroffset = $120;        {offset into MARK.COM where vector table is stored}
  23. TYPE
  24.   Block = RECORD              {store info about each memory block as it is found}
  25.             mcb : Integer;
  26.             psp : Integer;
  27.           END;
  28.   BlockType = 0..MaxBlocks;
  29.   BlockArray = ARRAY[BlockType] OF Block;
  30.   allstrings = STRING[255];
  31.  
  32. VAR
  33.   Blocks : BlockArray;
  34.   BottomBlock, BlockNum : BlockType;
  35.  
  36.   PROCEDURE FindTheBlocks;
  37.     {-scan memory for the allocated memory blocks}
  38.   CONST
  39.     MidBlockID = $4D;         {byte DOS uses to identify part of MCB chain}
  40.     EndBlockID = $5A;         {byte DOS uses to identify last block of MCB chain}
  41.   VAR
  42.     mcbSeg : Integer;         {potential segment address of an MCB}
  43.     nextSeg : Integer;        {computed segment address for the next MCB}
  44.     gotFirst : Boolean;       {true after first MCB is found}
  45.     gotLast : Boolean;        {true after last MCB is found}
  46.     idbyte : Byte;            {byte that DOS uses to identify an MCB}
  47.  
  48.     PROCEDURE StoreTheBlock(VAR mcbSeg, nextSeg : Integer;
  49.                             VAR gotFirst, gotLast : Boolean);
  50.       {-store information regarding the memory block}
  51.     VAR
  52.       nextID : Byte;
  53.       pspAdd : Integer;       {segment address of the current PSP}
  54.       mcbLen : Integer;       {size of the current memory block in paragraphs}
  55.     BEGIN
  56.  
  57.       mcbLen := MemW[mcbSeg:3]; {size of the MCB in paragraphs}
  58.       nextSeg := Succ(mcbSeg+mcbLen); {where the next MCB should be}
  59.       pspAdd := MemW[mcbSeg:1]; {address of program segment prefix for MCB}
  60.       nextID := Mem[nextSeg:0];
  61.  
  62.       IF gotLast OR (nextID = EndBlockID) OR (nextID = MidBlockID) THEN BEGIN
  63.         BlockNum := Succ(BlockNum);
  64.         gotFirst := True;
  65.         WITH Blocks[BlockNum] DO BEGIN
  66.           mcb := mcbSeg;
  67.           psp := pspAdd;
  68.         END;
  69.       END;
  70.  
  71.     END {storetheblock} ;
  72.  
  73.   BEGIN
  74.     {start above the Basic work area, could probably start even higher}
  75.     {there must be a magic address to start from, but it is not documented}
  76.     mcbSeg := $50;
  77.     gotFirst := False;
  78.     gotLast := False;
  79.     BlockNum := 0;
  80.  
  81.     {scan all memory until the last block is found}
  82.     REPEAT
  83.       idbyte := Mem[mcbSeg:0];
  84.       IF idbyte = MidBlockID THEN BEGIN
  85.         StoreTheBlock(mcbSeg, nextSeg, gotFirst, gotLast);
  86.         IF gotFirst THEN mcbSeg := nextSeg ELSE mcbSeg := Succ(mcbSeg);
  87.       END ELSE IF gotFirst AND (idbyte = EndBlockID) THEN BEGIN
  88.         gotLast := True;
  89.         StoreTheBlock(mcbSeg, nextSeg, gotFirst, gotLast);
  90.       END ELSE
  91.         {still looking for first block, try every paragraph boundary}
  92.         mcbSeg := Succ(mcbSeg);
  93.     UNTIL gotLast;
  94.  
  95.   END {findtheblocks} ;
  96.  
  97.   FUNCTION findmark(idstring : allstrings; idoffset : Integer) : Integer;
  98.     {-find the last memory block matching idstring at offset idoffset}
  99.   VAR
  100.     b : BlockType;
  101.     foundit : Boolean;
  102.  
  103.     FUNCTION MatchString(segment : Integer; idstring : allstrings; idoffset : Integer)
  104.       : Boolean;
  105.       {-return true if idstring is found at segment:idoffset}
  106.     VAR
  107.       tstring : allstrings;
  108.       len : Byte;
  109.     BEGIN
  110.       len := Length(idstring);
  111.       tstring[0] := Chr(len);
  112.       Move(Mem[segment:idoffset], tstring[1], len);
  113.       MatchString := (tstring = idstring);
  114.     END {matchstring};
  115.  
  116.   BEGIN
  117.     {scan from the last block-1 down to find the last MARK TSR}
  118.     b := Pred(BlockNum);
  119.     REPEAT
  120.       foundit := MatchString(Blocks[b].psp, idstring, idoffset);
  121.       IF NOT(foundit) THEN
  122.         b := Pred(b);
  123.     UNTIL (b < 1) OR foundit;
  124.     IF NOT(foundit) THEN BEGIN
  125.       WriteLn('No memory marker found. Mark memory by calling MARK.COM');
  126.       Halt(1);
  127.     END;
  128.     findmark := b;
  129.   END {findmark} ;
  130.  
  131.   PROCEDURE CopyVectors(BottomBlock : BlockType; vectoroffset : Integer);
  132.     {-put interrupt vectors back into table}
  133.   BEGIN
  134.     {interrupts off}
  135.     INLINE($FA);
  136.     {replace vectors}
  137.     Move(Mem[Blocks[BottomBlock].psp:vectoroffset], Mem[0:0], 1024);
  138.     {interrupts on}
  139.     INLINE($FB);
  140.   END {copyvectors} ;
  141.  
  142.   PROCEDURE ReleaseMem(BottomBlock : BlockType);
  143.     {release memory starting at block b, up to but not including this program}
  144.   TYPE
  145.     hexstring = STRING[4];
  146.   VAR
  147.     b : BlockType;
  148.     regs : RECORD
  149.              CASE Byte OF
  150.                1 : (ax, bx, cx, dx, bp, si, di, ds, es, flags : Integer);
  151.                2 : (al, ah, bl, bh, cl, ch, dl, dh : Byte);
  152.            END;
  153.  
  154.     FUNCTION Hex(i : Integer) : hexstring;
  155.       {-return hex representation of integer}
  156.     CONST
  157.       hc : ARRAY[0..15] OF Char = '0123456789ABCDEF';
  158.     VAR
  159.       l, h : Byte;
  160.     BEGIN
  161.       l := Lo(i); h := Hi(i);
  162.       Hex := hc[h SHR 4]+hc[h AND $F]+hc[l SHR 4]+hc[l AND $F];
  163.     END {hex} ;
  164.  
  165.   BEGIN
  166.     WITH regs DO
  167.       FOR b := BottomBlock TO (BlockNum-2) DO BEGIN
  168.         ah := $49;
  169.         {the block is always 1 paragraph above the MCB}
  170.         es := Succ(Blocks[b].mcb);
  171.         MsDos(regs);
  172.         IF Odd(flags) THEN BEGIN
  173.           WriteLn('Could not release block at segment ', Hex(es));
  174.           WriteLn('Memory is now a mess... Please reboot');
  175.           Halt(1);
  176.         END;
  177.       END;
  178.   END {releasemem} ;
  179.  
  180. BEGIN
  181.   WriteLn;
  182.   {get all allocated memory blocks}
  183.   FindTheBlocks;
  184.   {find the last one marked with the MARK idstring}
  185.   BottomBlock := findmark(markID, markOffset);
  186.   {copy the vector table from the MARK resident}
  187.   CopyVectors(BottomBlock, vectoroffset);
  188.   {release memory at and above the mark resident}
  189.   ReleaseMem(Pred(BottomBlock));
  190.   {DOS will release this program's memory when it exits}
  191.   {write success message}
  192.   WriteLn('Memory released above last MARK');
  193. END.
  194.