home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / SYSUTL / TSRSRC31.ZIP / MAPMEM.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1991-11-04  |  27.5 KB  |  972 lines

  1. {**************************************************************************
  2. *   MAPMEM - Reports system memory blocks.                                *
  3. *   Copyright (c) 1986,1991 Kim Kokkonen, TurboPower Software.            *
  4. *   May be freely distributed and used but not sold except by permission. *
  5. ***************************************************************************
  6. *   version 1.0 1/2/86                                                    *
  7. *   :                                                                     *
  8. *   long intervening history                                              *
  9. *   :                                                                     *
  10. *   version 3.0 9/24/91                                                   *
  11. *     completely rewritten for DOS 5 compatibility                        *
  12. *     add upper memory reporting                                          *
  13. *     add XMS reporting                                                   *
  14. *     add free memory report                                              *
  15. *     report on EMS handle names                                          *
  16. *     change command line switches                                        *
  17. *     add check for TSR feature                                           *
  18. *     add Quiet option (useful with "check for" option only)              *
  19. *     add summary report                                                  *
  20. *   version 3.1 11/4/91                                                   *
  21. *     fix bug in EMS handle reporting                                     *
  22. *     fix problem in getting name of TSR that shrinks environment (FSP)   *
  23. *     prevent from keeping interrupt 0                                    *
  24. *     fix source naming of WriteChained vs WriteHooked                    *
  25. *     show command line and vectors even if lower part of PSP is          *
  26. *       overwritten (DATAPATH)                                            *
  27. *     wouldn't find (using /C) a program whose name was stored in         *
  28. *       lowercase in the environment (Windows 3.0)                        *
  29. ***************************************************************************
  30. *   telephone: 719-260-6641, CompuServe: 76004,2611.                      *
  31. *   requires Turbo Pascal version 6 to compile.                           *
  32. ***************************************************************************}
  33.  
  34. {$R-,S-,I-,V-,B-,F-,A-,E-,N-,G-,X-}
  35. {$M 2048,0,655360}
  36.  
  37. program MapMem;
  38.  
  39. uses
  40.   Dos,
  41.   MemU,
  42.   Xms,
  43.   Ems;
  44.  
  45. const
  46.   Version = '3.1';
  47.   CheckTSR : Boolean = False;          {'C'}
  48.   ShowEmsMem : Boolean = False;        {'E'}
  49.   ShowFree : Boolean = False;          {'F'}
  50.   UseWatch : Boolean = True;           {'H'}
  51.   Quiet : Boolean = False;             {'Q'}
  52.   ShowSummary : Boolean = False;       {'S'}
  53.   ShowHiMem : Boolean = False;         {'U'}
  54.   Verbose : Boolean = False;           {'V'}
  55.   ShowExtMem : Boolean = False;        {'X'}
  56.  
  57. var
  58.   TotalMem : LongInt;
  59.   TopSeg : Word;
  60.   WatchPsp : Word;
  61.   ShowDevices : Boolean;
  62.   ShowSegments : Boolean;
  63.   ShowBlocks : Boolean;
  64.   ShowFiles : Boolean;
  65.   ShowVectors : Boolean;
  66.   GotXms : Boolean;
  67.   SizeLen : Byte;
  68.   NameLen : Byte;
  69.   CmdLen : Byte;
  70.   UmbLinkStatus : Boolean;
  71.   SaveExit : Pointer;
  72.   TsrName : string[79];
  73.  
  74. const
  75.   FreeName  : string[10] = '---free---';
  76.   TotalName : string[10] = '---total--';
  77.  
  78. const
  79.   VerboseIndent = 5;
  80.   NoShowVecSeg = $FFFE;
  81.   ShowVecSeg   = $FFFF;
  82.  
  83.   procedure SafeExit; far;
  84.   var
  85.     Status : Word;
  86.   begin
  87.     ExitProc := SaveExit;
  88.     SwapVectors;
  89.     if HiMemAvailable(DosV) then
  90.       Status := SetUmbLinkStatus(UmbLinkStatus);
  91.   end;
  92.  
  93.   function GetName(M : McbPtr; var Devices : Boolean) : String;
  94.     {-Return a name for Mcb M}
  95.   const
  96.     EnvName : array[boolean] of string[4] = ('', 'env');
  97.     DatName : array[boolean] of string[4] = ('', 'data');
  98.   var
  99.     PspSeg : Word;
  100.     IsCmd : Boolean;
  101.   begin
  102.     Devices := False;
  103.     PspSeg := M^.Psp;
  104.  
  105.     if (PspSeg = 0) or (PspSeg = PrefixSeg) then
  106.       GetName := FreeName
  107.     else if PspSeg = 8 then begin
  108.       GetName := 'system data';
  109.       if DosV = 5 then
  110.         if (M^.Name[1] = 'S') and (M^.Name[2] = 'D') then begin
  111.           GetName := 'config info';
  112.           Devices := True;
  113.         end;
  114.     end else if PspSeg >= $FFF0 then
  115.       GetName := 'unavailable'
  116.     else if PspSeg = OS(M).S+1 then begin
  117.       {program block}
  118.       IsCmd := (PspSeg = MemW[PspSeg:$16]);
  119.       if (not IsCmd) and (DosV > 2) and HasEnvironment(M) then
  120.         GetName := NameFromEnv(M)
  121.       else if DosV >= 5 then
  122.         GetName := NameFromMcb(M)
  123.       else if IsCmd then
  124.         GetName := 'command'
  125.       else
  126.         GetName := 'n/a';
  127.     end else if MemW[PspSeg:$2C] = OS(M).S+1 then
  128.       GetName := EnvName[Verbose]+'('+GetName(Ptr(PspSeg-1, 0), Devices)+')'
  129.     else
  130.       GetName := DatName[Verbose]+'('+GetName(Ptr(PspSeg-1, 0), Devices)+')';
  131.   end;
  132.  
  133.   function ValidPsp(PspSeg : Word) : Boolean;
  134.     {-Return True if PspSeg is a valid Psp}
  135.   begin
  136.     if (PspSeg = 0) or (PspSeg = PrefixSeg) or
  137.        (PspSeg = 8) or (PspSeg >= $FFF0) then
  138.       ValidPsp := False
  139.     else
  140.        ValidPsp := True;
  141.   end;
  142.  
  143.   function GetFiles(M : McbPtr) : Word;
  144.     {-Return number of open files for given Mcb's Psp}
  145.   type
  146.     HandleTable = array[0..65520] of Byte;
  147.   var
  148.     PspSeg : Word;
  149.     O : Word;
  150.     Files : Word;
  151.     FileMax : Word;
  152.     TablePtr : ^HandleTable;
  153.   begin
  154.     PspSeg := M^.Psp;
  155.     if (PspSeg <> OS(M).S+1) or not ValidPsp(PspSeg) or
  156.        (MemW[PspSeg:$50] <> $21CD) then begin
  157.       GetFiles := 0;
  158.       Exit;
  159.     end;
  160.     {Deal with expanded handle tables in DOS 3.0 and later}
  161.     if DosV >= 3 then begin
  162.       FileMax := MemW[M^.Psp:$32];
  163.       TablePtr := Pointer(MemL[M^.Psp:$34]);
  164.     end else begin
  165.       FileMax := 20;
  166.       TablePtr := Ptr(M^.Psp, $18);
  167.     end;
  168.  
  169.     Files := 0;
  170.     for O := 0 to FileMax-1 do
  171.       case TablePtr^[O] of
  172.         0, 1, 2, $FF : {standard handle or not open} ;
  173.       else
  174.         Inc(Files);
  175.       end;
  176.     GetFiles := Files;
  177.   end;
  178.  
  179.   function GetCmdLine(M : McbPtr) : String;
  180.     {-Return command line for program}
  181.   var
  182.     PspSeg : Word;
  183.     S : String[127];
  184.   begin
  185.     PspSeg := M^.Psp;
  186.     if (PspSeg <> OS(M).S+1) or not ValidPsp(PspSeg) then begin
  187.       GetCmdLine := '';
  188.       Exit;
  189.     end;
  190.     Move(Mem[PspSeg:$80], S, 127);
  191.     if S <> '' then begin
  192.       StripNonAscii(S);
  193.       if S = '' then
  194.         S := 'n/a';
  195.     end;
  196.     while (Length(S) > 0) and (S[1] = ' ') do
  197.       Delete(S, 1, 1);
  198.     GetCmdLine := S;
  199.   end;
  200.  
  201.   procedure WriteHooked(LowSeg, HighSeg : Word; StartCol, WrapCol : Byte);
  202.     {-Write vectors that point into specified region of memory}
  203.   var
  204.     Vectors : array[0..255] of Pointer absolute 0:0;
  205.     Vec : Pointer;
  206.     LoL : LongInt;
  207.     HiL : LongInt;
  208.     VeL : LongInt;
  209.     V : Byte;
  210.     Col : Byte;
  211.   begin
  212.     LoL := LongInt(LowSeg) shl 4;
  213.     HiL := LongInt(HighSeg) shl 4;
  214.     Col := StartCol;
  215.     for V := 0 to 255 do begin
  216.       Vec := Vectors[V];
  217.       VeL := (LongInt(OS(Vec).S) shl 4)+OS(Vec).O;
  218.       if (VeL >= LoL) and (VeL < HiL) then begin
  219.         if Col+3 > WrapCol then begin
  220.           {wrap to next line}
  221.           Write(^M^J, '':StartCol-1);
  222.           Col := StartCol;
  223.         end;
  224.         Write(HexB(V), ' ');
  225.         inc(Col, 3);
  226.       end;
  227.     end;
  228.   end;
  229.  
  230.   procedure WriteChained(PspSeg : Word; StartCol, WrapCol : Byte);
  231.     {-Write vectors that WATCH found taken over by a block}
  232.   var
  233.     P : ^ChangeBlock;
  234.     I, MaxChg, Col : Word;
  235.     Found : Boolean;
  236.   begin
  237.     {initialize}
  238.     MaxChg := MemW[WatchPsp:NextChange];
  239.     Col := StartCol;
  240.     Found := False;
  241.     I := 0;
  242.  
  243.     while I < MaxChg do begin
  244.       P := Ptr(WatchPsp, ChangeVectors+I);
  245.       with P^ do
  246.         case ID of
  247.           $00 :           {ChangeBlock describes an active vector takeover}
  248.             if Found then begin
  249.               if Col+3 > WrapCol then begin
  250.                 {wrap to next line}
  251.                 Write(^M^J, '':StartCol-1);
  252.                 Col := StartCol;
  253.               end;
  254.               Write(HexB(Lo(VecNum)), ' ');
  255.               inc(Col, 3);
  256.             end;
  257.           $01 :           {ChangeBlock specifies a disabled takeover}
  258.             if Found then begin
  259.               Write('disabled');
  260.               {Don't write this more than once}
  261.               Exit;
  262.             end;
  263.           $FF :           {ChangeBlock starts a new PSP}
  264.             Found := (PspSeg = PspAdd);
  265.         end;
  266.       inc(I, SizeOf(ChangeBlock));
  267.     end;
  268.   end;
  269.  
  270.   procedure WriteVectors(LowSeg, HighSeg : Word; StartCol, WrapCol : Byte);
  271.     {-Write interrupt vectors either hooked or chained}
  272.   begin
  273.     if UseWatch then
  274.       WriteChained(LowSeg, StartCol, WrapCol)
  275.     else
  276.       WriteHooked(LowSeg, HighSeg, StartCol, WrapCol);
  277.   end;
  278.  
  279.   procedure WriteMcb(McbSeg, PspSeg, Paras, Blocks, Files : Word;
  280.                      Name : String; CmdLine : String);
  281.     {-Write information about one Mcb or group of mcbs}
  282.   var
  283.     Col : Byte;
  284.   begin
  285.     Col := 1;
  286.  
  287.     if ShowSegments then begin
  288.       case McbSeg of
  289.         NoShowVecSeg, ShowVecSeg : ;
  290.       else
  291.         Write(HexW(McbSeg), ' ');
  292.         inc(Col, 5);
  293.       end;
  294.  
  295.       if (PspSeg = 0) or (PspSeg = 8) then
  296.         Write('    ')
  297.       else
  298.         Write(HexW(PspSeg));
  299.       inc(Col, 4);
  300.     end else
  301.       Write('  ');
  302.  
  303.     if ShowBlocks then begin
  304.       Write(' ', Blocks:2);
  305.       inc(Col, 3);
  306.     end;
  307.  
  308.     if ShowFiles then begin
  309.       if Files = 0 then
  310.         Write('   ')
  311.       else
  312.         Write(' ', Files:2);
  313.       inc(Col, 3);
  314.     end;
  315.  
  316.     Write(' ', CommaIze(LongInt(Paras) shl 4, SizeLen),
  317.           ' ', Extend(Name, NameLen),
  318.           ' ', SmartExtend(CmdLine, CmdLen));
  319.     inc(Col, 3+SizeLen+NameLen+CmdLen);
  320.  
  321.     if ShowVectors then
  322.       if (PspSeg = McbSeg+1) or (McbSeg = ShowVecSeg) then
  323.         if ValidPsp(PspSeg) then begin
  324.           Write(' ');
  325.           WriteVectors(PspSeg, PspSeg+Paras, Col+1, 79);
  326.         end;
  327.  
  328.     WriteLn;
  329.  
  330.     {keep track of total reported memory}
  331.     Inc(TotalMem, Paras);
  332.     Inc(TotalMem, Blocks);        {for the mcbs themselves}
  333.   end;
  334.  
  335.   procedure WriteDevices(DevSeg, NextSeg : Word);
  336.     {-Write the DOS 5 device list}
  337.   var
  338.     D : McbPtr;
  339.     Name : String[79];
  340.   begin
  341.     D := Ptr(DevSeg, 0);
  342.     while OS(D).S < NextSeg do begin
  343.       case D^.Id of
  344.         'B' : Name := 'buffers';
  345.         'C' : Name := 'ems buffers';
  346.         'D' : Name := 'device='+Asc2Str(D^.Name);
  347.         'E' : Name := 'device ext';
  348.         'F' : Name := 'files';
  349.         'I' : Name := 'ifs='+Asc2Str(D^.Name);
  350.         'L' : Name := 'lastdrive';
  351.         'S' : Name := 'stacks';
  352.         'X' : Name := 'fcbs';
  353.       else
  354.         Name := '';
  355.       end;
  356.       if Name <> '' then
  357.         WriteLn('':20, (LongInt(D^.Len+1) shl 4):6, ' ', Name);
  358.       D := Ptr(OS(D).S+D^.Len+1, 0);
  359.     end;
  360.   end;
  361.  
  362.   procedure WriteTotalMem;
  363.     {-Write total reported memory with leading space PreSpace}
  364.   var
  365.     PreSpace : Word;
  366.   begin
  367.     if TotalMem <> 0 then begin
  368.       PreSpace := 7;
  369.       if Verbose then
  370.         inc(PreSpace, VerboseIndent);
  371.       WriteLn('':PreSpace, CommaIze(LongInt(TotalMem) shl 4, 8), ' ', TotalName);
  372.       TotalMem := 0;
  373.     end;
  374.   end;
  375.  
  376.   procedure FindTSR;
  377.     {-Find TSRName, report if appropriate, and halt}
  378.   var
  379.     M : McbPtr;
  380.     PspSeg : Word;
  381.     Done : Boolean;
  382.     Devices : Boolean;
  383.     IsCmd : Boolean;
  384.     Name : String[79];
  385.   begin
  386.     M := Mcb1;
  387.     repeat
  388.       PspSeg := M^.Psp;
  389.       if OS(M).S+1 = PspSeg then begin
  390.         IsCmd := (PspSeg = MemW[PspSeg:$16]);
  391.         if (not IsCmd) and (DosV > 2) and HasEnvironment(M) then
  392.           Name := NameFromEnv(M)
  393.         else if DosV >= 4 then
  394.           Name := NameFromMcb(M)
  395.         else
  396.           Name := '';
  397.         if StUpcase(Name) = TsrName then begin
  398.           if not Quiet then
  399.             WriteLn('Found ', TsrName, ' at ', HexW(PspSeg));
  400.           Halt(0);
  401.         end;
  402.       end;
  403.       Done := (M^.Id = 'Z');
  404.       M := Ptr(OS(M).S+M^.Len+1, 0);
  405.     until Done;
  406.     {Not found if we get here}
  407.     Halt(2);
  408.   end;
  409.  
  410.   procedure WriteVerbose;
  411.     {-Report on each Mcb individually}
  412.   var
  413.     M : McbPtr;
  414.     Done : Boolean;
  415.     Pending : Boolean;
  416.   begin
  417.     Write('Mcb  Psp  Hdl   Size Name           Command Line        ');
  418.     if UseWatch then
  419.       Write('Chained')
  420.     else
  421.       Write('Hooked');
  422.     WriteLn(' Vectors');
  423.     WriteLn('---- ---- --- ------ -------------- ------------------- -----------------------');
  424.  
  425.     {fake Mcb's used by dos itself}
  426.     WriteMcb($0000, $0000, $0040, 0, 0, 'vectors', '');
  427.     WriteMcb($0040, $0000, $0010, 0, 0, 'BIOS data', '');
  428.     WriteMcb($0050, $0000, $0020, 0, 0, 'DOS data', '');
  429.     WriteMcb($0070, $0000, OS(DosList).S-$70, 0, 0, 'system data', '');
  430.     WriteMcb(OS(DosList).S, $0000, OS(Mcb1).S-OS(DosList).S, 0, 0, 'system code', '');
  431.  
  432.     M := Mcb1;
  433.     Pending := True;
  434.     repeat
  435.       if Pending and (OS(M).S+1 >= TopSeg) then begin
  436.         WriteTotalMem;
  437.         WriteLn(^M^J'High Memory');
  438.         Pending := False;
  439.       end;
  440.       WriteMcb(OS(M).S, M^.Psp, M^.Len, 1,
  441.                GetFiles(M), GetName(M, ShowDevices), GetCmdLine(M));
  442.       if ShowDevices then
  443.         WriteDevices(OS(M).S+1, OS(M).S+M^.Len+1);
  444.       Done := (M^.Id = 'Z');
  445.       M := Ptr(OS(M).S+M^.Len+1, 0);
  446.     until Done;
  447.     WriteTotalMem;
  448.   end;
  449.  
  450.   function McbsInHiMem : Boolean;
  451.     {-Return True if any Mcbs found in high memory}
  452.   var
  453.     M : McbPtr;
  454.     Done : Boolean;
  455.   begin
  456.     M := Mcb1;
  457.     repeat
  458.       if OS(M).S >= TopSeg-1 then begin
  459.         McbsInHiMem := True;
  460.         Exit;
  461.       end;
  462.       Done := (M^.Id = 'Z');
  463.       M := Ptr(OS(M).S+M^.Len+1, 0);
  464.     until Done;
  465.     McbsInHiMem := False;
  466.   end;
  467.  
  468.   procedure SummarizePsp(TPsp, LoMcb, HiMcb : Word);
  469.     {-Write info about all Mcbs in range LoMcb..HiMcb with the specified Psp}
  470.   var
  471.     TM : McbPtr;
  472.     M : McbPtr;
  473.     Size : Word;
  474.     Blocks : Word;
  475.     FakeSeg : Word;
  476.     MPsp : Word;
  477.     Done : Boolean;
  478.     HaveCodeBlock : Boolean;
  479.   begin
  480.     Size := 0;
  481.     Blocks := 0;
  482.     M := Mcb1;
  483.     TM := nil;
  484.     HaveCodeBlock := False;
  485.     repeat
  486.       MPsp := M^.Psp;
  487.       if MPsp = 0 then
  488.         MPsp := OS(M).S;
  489.       if MPsp = TPsp then begin
  490.         if (OS(M).S >= LoMcb) and (OS(M).S < HiMcb) then begin
  491.           Inc(Size, M^.Len);
  492.           Inc(Blocks);
  493.           if OS(M).S+1 = TPsp then
  494.             HaveCodeBlock := True;
  495.         end;
  496.         if TM = nil then
  497.           TM := M
  498.         else if M^.Psp = OS(M).S+1 then
  499.           TM := M;
  500.       end;
  501.       Done := (M^.Id = 'Z');
  502.       M := Ptr(OS(M).S+M^.Len+1, 0);
  503.     until Done;
  504.  
  505.     if Blocks > 0 then begin
  506.       if HaveCodeBlock then
  507.         FakeSeg := ShowVecSeg
  508.       else
  509.         FakeSeg := NoShowVecSeg;
  510.       WriteMcb(FakeSeg, TM^.Psp, Size, Blocks, 0,
  511.                GetName(TM, ShowDevices), GetCmdLine(TM));
  512.     end;
  513.   end;
  514.  
  515.   procedure SummarizeRange(LoMcb, HiMcb : Word);
  516.     {-Summarize Psps in the range LoMcb..HiMcb,
  517.       for Psp > 8, Psp < $FFF0, and Psp <> PrefixSeg}
  518.   var
  519.     M : McbPtr;
  520.     MinPsp : Word;
  521.     TPsp : Word;
  522.     PrvPsp : Word;
  523.     Done : Boolean;
  524.   begin
  525.     PrvPsp := 8;
  526.     repeat
  527.       {find the smallest Psp not yet summarized}
  528.       MinPsp := $FFFF;
  529.       M := Mcb1;
  530.       repeat
  531.         TPsp := M^.Psp;
  532.         if TPsp = 0 then
  533.           TPsp := OS(M).S;
  534.         if TPsp < MinPsp then
  535.           if (TPsp > PrvPsp) and (TPsp < $FFF0) and (TPsp <> PrefixSeg) then
  536.             MinPsp := TPsp;
  537.         Done := (M^.Id = 'Z');
  538.         M := Ptr(OS(M).S+M^.Len+1, 0);
  539.       until Done;
  540.  
  541.       if MinPsp <> $FFFF then begin
  542.         {add up info about this Psp}
  543.         SummarizePsp(MinPsp, LoMcb, HiMcb);
  544.         {"mark out" this Psp}
  545.         PrvPsp := MinPsp;
  546.       end;
  547.     until MinPsp = $FFFF;
  548.   end;
  549.  
  550.   procedure SummarizeDos(LoMcb, HiMcb : Word);
  551.     {-Sum up memory attributed to DOS}
  552.   var
  553.     M : McbPtr;
  554.     Size : Word;
  555.     Blocks : Word;
  556.     FakeSeg : Word;
  557.     Done : Boolean;
  558.   begin
  559.     M := Mcb1;
  560.     Size := 0;
  561.     Blocks := 0;
  562.     repeat
  563.       if M^.Psp = 8 then
  564.         if (OS(M).S >= LoMcb) and (OS(M).S < HiMcb) then begin
  565.           Inc(Size, M^.Len);
  566.           Inc(Blocks);
  567.         end;
  568.       Done := (M^.Id = 'Z');
  569.       M := Ptr(OS(M).S+M^.Len+1, 0);
  570.     until Done;
  571.     if Blocks > 0 then begin
  572.       if HiMcb > TopSeg then
  573.         FakeSeg := NoShowVecSeg
  574.       else
  575.         FakeSeg := ShowVecSeg;
  576.       WriteMcb(FakeSeg, $00, OS(Mcb1).S+Size, Blocks, 0, 'DOS', '');
  577.     end;
  578.   end;
  579.  
  580.   procedure SummarizeFree(LoMcb, HiMcb : Word);
  581.     {-Write the free memory blocks in specified range of Mcbs}
  582.   var
  583.     M : McbPtr;
  584.     Done : Boolean;
  585.   begin
  586.     M := Mcb1;
  587.     repeat
  588.       if (M^.Psp = 0) and (M^.Len > 0) and
  589.          (OS(M).S >= LoMcb) and (OS(M).S < HiMcb) then
  590.         WriteMcb(NoShowVecSeg, $0000, M^.Len, 1, 0, FreeName, '');
  591.       Done := (M^.Id = 'Z');
  592.       M := Ptr(OS(M).S+M^.Len+1, 0);
  593.     until Done;
  594.   end;
  595.  
  596.   procedure WriteCondensed;
  597.     {-Report on Mcb's by Psp}
  598.   begin
  599.     Write('Psp  Cnt   Size Name       Command Line        ');
  600.     if UseWatch then
  601.       Write('Chained')
  602.     else
  603.       Write('Hooked');
  604.     WriteLn(' Vectors');
  605.     WriteLn('---- --- ------ ---------- ------------------- --------------------------------');
  606.  
  607.     SummarizeDos(0, TopSeg-1);          {DOS memory usage}
  608.     SummarizeRange(0, TopSeg-1);        {programs loaded in low memory}
  609.     SummarizePsp(PrefixSeg, 0, $FFFF);  {current program free space}
  610.     WriteTotalMem;                      {sum of memory so far}
  611.  
  612.     if ShowHiMem and McbsInHiMem then begin
  613.       WriteLn(^M^J'High Memory');
  614.       SummarizeDos(TopSeg-1, $FFFF);
  615.       SummarizeRange(TopSeg-1, $FFFF);
  616.       WriteTotalMem;
  617.     end;
  618.   end;
  619.  
  620.   procedure WriteFree;
  621.     {-Show just the free blocks in conventional memory}
  622.   begin
  623.     WriteLn('Normal Memory');
  624.     SummarizeFree(0, TopSeg-1);         {free blocks in low memory}
  625.     SummarizePsp(PrefixSeg, 0, $FFFF);  {current program free space}
  626.  
  627.     if ShowHiMem and McbsInHiMem then begin
  628.       WriteLn(^M^J'High Memory');
  629.       SummarizeFree(TopSeg-1, $FFFF);
  630.     end;
  631.   end;
  632.  
  633.   procedure WriteSummary;
  634.     {-Write "summary" report for conventional memory}
  635.   begin
  636.     WriteLn('      Size Name       Command Line');
  637.     WriteLn('---------- ---------- --------------------------------------------------------');
  638.  
  639.     SummarizeDos(0, TopSeg-1);          {DOS memory usage}
  640.     SummarizeRange(0, TopSeg-1);        {programs loaded in low memory}
  641.     SummarizePsp(PrefixSeg, 0, $FFFF);  {current program free space}
  642.  
  643.     if ShowHiMem and McbsInHiMem then begin
  644.       WriteLn(^M^J'High Memory');
  645.       SummarizeDos(TopSeg-1, $FFFF);
  646.       SummarizeRange(TopSeg-1, $FFFF);
  647.     end;
  648.   end;
  649.  
  650.   procedure ShowConventionalMem;
  651.     {-Report on conventional memory, low and high}
  652.   begin
  653.     {Default values for display}
  654.     ShowSegments := True;
  655.     ShowBlocks := False;
  656.     ShowFiles := False;
  657.     ShowVectors := True;
  658.     SizeLen := 7;
  659.     NameLen := 10;
  660.     CmdLen := 19;
  661.  
  662.     if ShowFree then begin
  663.       ShowSegments := False;
  664.       ShowVectors := False;
  665.       WriteFree;
  666.     end else if ShowSummary then begin
  667.       ShowSegments := False;
  668.       ShowVectors := False;
  669.       CmdLen := 56;
  670.       WriteSummary;
  671.     end else if Verbose then begin
  672.       ShowFiles := True;
  673.       NameLen := 14;
  674.       WriteVerbose;
  675.     end else begin
  676.       ShowBlocks := True;
  677.       WriteCondensed;
  678.     end;
  679.   end;
  680.  
  681.   procedure ShowTheEmsMem;
  682.   var
  683.     Handles : Word;
  684.     H : Word;
  685.     P : Word;
  686.     Pages : LongInt;
  687.     EmsV : Byte;
  688.     PreSpace : Byte;
  689.     Name : string[9];
  690.     PageMap : PageArray;
  691.   begin
  692.     if not EmsPresent then
  693.       Exit;
  694.     WriteLn;
  695.     WriteLn('EMS Memory');
  696.     if not(ShowFree or ShowSummary) then begin
  697.       EmsV := EmsVersion;
  698.       Handles := EmsHandles(PageMap);
  699.       if Handles > 0 then
  700.         for H := 1 to Handles do begin {!!}
  701.           P := PageMap[H].NumPages;
  702.           if P <> 0 then begin
  703.             Write(HexW(H), ' ');
  704.             if Verbose then
  705.               Write('':VerboseIndent);
  706.             Write(CommaIze(LongInt(P) shl 14, 10));
  707.             if EmsV >= $40 then begin
  708.               GetHandleName(PageMap[H].Handle, Name);
  709.               if Name = '' then
  710.                 Name := 'n/a';
  711.             end else
  712.               Name := 'n/a';
  713.             WriteLn(' ', Name);
  714.           end;
  715.         end;
  716.     end;
  717.     Pages := EmsPagesAvailable;
  718.     if ShowFree or ShowSummary then
  719.       PreSpace := 0
  720.     else
  721.       PreSpace := 5;
  722.     if Verbose then
  723.       inc(PreSpace, VerboseIndent);
  724.     WriteLn('':PreSpace, CommaIze(LongInt(OS(Pages).O) shl 14, 10), ' ', FreeName);
  725.     if ShowSummary or (not ShowFree) then
  726.       WriteLn('':PreSpace, CommaIze(LongInt(OS(Pages).S) shl 14, 10), ' ', TotalName);
  727.   end;
  728.  
  729.   procedure ShowTheXmsMem;
  730.     {-Show what we can about XMS}
  731.   label
  732.     ExitPoint;
  733.   var
  734.     FMem : Word;
  735.     FMax : Word;
  736.     XHandles : Word;
  737.     H : Word;
  738.     HMem : Word;
  739.     Total : Word;
  740.     XmsPages : XmsHandlesPtr;
  741.     Status : Byte;
  742.     PreSpace : Byte;
  743.   begin
  744.     if not XmsInstalled then
  745.       Exit;
  746.     Status := QueryFreeExtMem(FMem, FMax);
  747.     if Status = $A0 then begin
  748.       FMem := 0;
  749.       FMax := 0;
  750.     end else if Status <> 0 then
  751.       Exit;
  752.  
  753.     {Total will count total XMS memory}
  754.     Total := 0;
  755.  
  756.     WriteLn(^M^J'XMS Memory');
  757.     GotXms := not Verbose;
  758.  
  759.     if ShowFree then
  760.       goto ExitPoint;
  761.  
  762.     {Get an array containing handles}
  763.     XHandles := GetXmsHandles(XmsPages);
  764.  
  765.     {Report all the handles}
  766.     for H := 1 to XHandles do begin
  767.       HMem := XmsPages^[H].NumPages;
  768.       if not ShowSummary then begin
  769.         Write(HexW(H), ' ');
  770.         if Verbose then
  771.           Write('':VerboseIndent);
  772.         WriteLn(CommaIze(LongInt(HMem) shl 10, 10), ' n/a');
  773.       end;
  774.       inc(Total, HMem);
  775.     end;
  776.  
  777.     {Add the free memory to the total}
  778.     inc(Total, FMem);
  779.  
  780. ExitPoint:
  781.     if ShowFree or ShowSummary then
  782.       PreSpace := 0
  783.     else
  784.       PreSpace := 5;
  785.     if Verbose then
  786.       inc(PreSpace, VerboseIndent);
  787.     WriteLn('':PreSpace, CommaIze(LongInt(FMem) shl 10, 10), ' ', FreeName);
  788.     if Total <> 0 then
  789.       WriteLn('':PreSpace, CommaIze(LongInt(Total) shl 10, 10), ' ', TotalName);
  790.   end;
  791.  
  792.   procedure ShowTheExtendedMem;
  793.   var
  794.     Total : LongInt;
  795.     PreSpace : Byte;
  796.   begin
  797.     if GotXms or ShowFree then
  798.       Exit;
  799.     if ExtMemPossible then
  800.       Total := ExtMemTotalPrim
  801.     else
  802.       Total := 0;
  803.     if Total = 0 then
  804.       Exit;
  805.  
  806.     WriteLn(^M^J'Raw Extended Memory');
  807.     PreSpace := 5;
  808.     if Verbose then
  809.       inc(PreSpace, VerboseIndent);
  810.     WriteLn('':PreSpace, CommaIze(Total, 10), ' ', TotalName);
  811.   end;
  812.  
  813.   procedure WriteCopyright;
  814.     {-Write a copyright message}
  815.   begin
  816.     Write('MAPMEM ', Version, ', Copyright 1991 TurboPower Software'^M^J^M^J);
  817.   end;
  818.  
  819.   procedure Initialize;
  820.     {-Initialize various global variables}
  821.   begin
  822.     GotXms := False;
  823.     TotalMem := 0;
  824.     TopSeg := TopOfMemSeg;
  825.   end;
  826.  
  827.   procedure GetOptions;
  828.     {-Parse command line and set options}
  829.   var
  830.     I : Word;
  831.     Status : Word;
  832.     Arg : String[127];
  833.  
  834.     procedure WriteHelp;
  835.     begin
  836.       WriteCopyright;
  837.       WriteLn('MAPMEM produces a report showing what memory resident programs are installed,');
  838.       WriteLn('how much memory each uses, and what interrupt vectors are taken over.');
  839.       WriteLn;
  840.       WriteLn('MAPMEM accepts the following command line syntax:');
  841.       WriteLn;
  842.       WriteLn('  MAPMEM [Options]');
  843.       WriteLn;
  844.       WriteLn('Options may be preceded by either / or -. Valid options are as follows:');
  845.       WriteLn('     /C name  check whether TSR "name" is loaded.');
  846.       WriteLn('     /E       report expanded (EMS) memory.');
  847.       WriteLn('     /F       report free areas only.');
  848.       WriteLn('     /H       do not use WATCH information for vectors.');
  849.       WriteLn('     /Q       write no screen output with /C option.');
  850.       WriteLn('     /S       show summary of all memory areas.');
  851.       WriteLn('     /U       report upper memory blocks (DOS 5).');
  852.       WriteLn('     /V       verbose report.');
  853.       WriteLn('     /X       report extended (XMS) memory.');
  854.       WriteLn('     /?       write this help screen.');
  855.       Halt(1);
  856.     end;
  857.  
  858.     procedure UnknownOption;
  859.     begin
  860.       WriteCopyright;
  861.       WriteLn('Unknown command line option: ', Arg);
  862.       Halt(1);
  863.     end;
  864.  
  865.     procedure BadOption;
  866.     begin
  867.       WriteCopyright;
  868.       WriteLn('Invalid command line option: ', Arg);
  869.       Halt(1);
  870.     end;
  871.  
  872.   begin
  873.     TsrName := '';
  874.  
  875.     I := 1;
  876.     while I <= ParamCount do begin
  877.       Arg := ParamStr(I);
  878.       if Arg = '?' then
  879.         WriteHelp
  880.       else
  881.         case Arg[1] of
  882.           '-', '/' :
  883.             case Length(Arg) of
  884.               1 : BadOption;
  885.               2 : case Upcase(Arg[2]) of
  886.                     '?' : WriteHelp;
  887.                     'C' : begin
  888.                             CheckTSR := not CheckTSR;
  889.                             if CheckTSR then begin
  890.                               if I = ParamCount then begin
  891.                                 WriteCopyright;
  892.                                 WriteLn('TSR name to check for is missing');
  893.                                 Halt(1);
  894.                               end;
  895.                               inc(I);
  896.                               TsrName := StUpcase(ParamStr(I));
  897.                             end;
  898.                           end;
  899.                     'E' : ShowEmsMem := not ShowEmsMem;
  900.                     'F' : ShowFree := not ShowFree;
  901.                     'H' : UseWatch := not UseWatch;
  902.                     'Q' : Quiet := not Quiet;
  903.                     'S' : ShowSummary := not ShowSummary;
  904.                     'U' : ShowHiMem := not ShowHiMem;
  905.                     'V' : Verbose := not Verbose;
  906.                     'X' : ShowExtMem := not ShowExtMem;
  907.                   else
  908.                     BadOption;
  909.                   end;
  910.             else
  911.               UnknownOption;
  912.             end;
  913.         else
  914.           UnknownOption;
  915.         end;
  916.       Inc(I);
  917.     end;
  918.  
  919.     {Account for related options}
  920.     if ShowFree then
  921.       ShowSummary := False;
  922.     if ShowFree or ShowSummary then begin
  923.       ShowHiMem := True;
  924.       ShowEmsMem := True;
  925.       ShowExtMem := True;
  926.       Verbose := False;
  927.     end;
  928.     if not CheckTSR then
  929.       Quiet := False;
  930.  
  931.     {Initialize for high memory access}
  932.     if HiMemAvailable(DosV) then begin
  933.       UmbLinkStatus := GetUmbLinkStatus;
  934.       if SetUmbLinkStatus(ShowHiMem) <> 0 then
  935.         ShowHiMem := False;
  936.     end else
  937.       ShowHiMem := False;
  938.  
  939.     {Don't report any vectors normally taken over by SYSTEM}
  940.     SwapVectors;
  941.  
  942.     {ExitProc will undo swap and restore high memory access}
  943.     SaveExit := ExitProc;
  944.     ExitProc := @SafeExit;
  945.  
  946.     {Find WATCH in memory if requested}
  947.     if UseWatch then begin
  948.       WatchPsp := WatchPspSeg;
  949.       if WatchPsp = 0 then
  950.         UseWatch := False;
  951.     end;
  952.  
  953.     if not Quiet then
  954.       WriteCopyright;
  955.   end;
  956.  
  957. begin
  958.   Initialize;
  959.   GetOptions;
  960.   if CheckTSR then
  961.     FindTSR
  962.   else begin
  963.     ShowConventionalMem;
  964.     if ShowEmsMem then
  965.       ShowTheEmsMem;
  966.     if ShowExtMem then begin
  967.       ShowTheXmsMem;
  968.       ShowTheExtendedMem;
  969.     end;
  970.   end;
  971. end.
  972.