home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / environ / tpenv.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1988-11-07  |  14.7 KB  |  592 lines

  1. {$R-,S-,V-,I-,B-,F-}
  2.  
  3. {Disable the following define if you don't have Turbo Professional}
  4. {$DEFINE UseTpro}
  5.  
  6. {*********************************************************}
  7. {*                    TPENV.PAS 1.01                     *}
  8. {*                by TurboPower Software                 *}
  9. {*********************************************************}
  10.  
  11. {
  12.   Version 1.01 11/7/88
  13.     Find master environment in DOS 3.3 and 4.0
  14. }
  15.  
  16. unit TpEnv;
  17.   {-Manipulate the environment}
  18.  
  19. interface
  20.  
  21.   {$IFDEF UseTpro}
  22. uses
  23.   TpString,
  24.   TpDos;
  25.   {$ENDIF}
  26.  
  27. type
  28.   EnvArray = array[0..32767] of Char;
  29.   EnvArrayPtr = ^EnvArray;
  30.   EnvRec =
  31.     record
  32.       EnvSeg : Word;              {Segment of the environment}
  33.       EnvLen : Word;              {Usable length of the environment}
  34.       EnvPtr : Pointer;           {Nil except when allocated on heap}
  35.     end;
  36.  
  37. const
  38.   ShellUserProc : Pointer = nil;  {Put address of ExecDos user proc here if desired}
  39.  
  40. procedure MasterEnv(var Env : EnvRec);
  41.   {-Return master environment record}
  42.  
  43. procedure CurrentEnv(var Env : EnvRec);
  44.   {-Return current environment record}
  45.  
  46. procedure NewEnv(var Env : EnvRec; Size : Word);
  47.   {-Allocate a new environment on the heap}
  48.  
  49. procedure DisposeEnv(var Env : EnvRec);
  50.   {-Deallocate an environment previously allocated on heap}
  51.  
  52. procedure SetCurrentEnv(Env : EnvRec);
  53.   {-Specify a different environment for the current program}
  54.  
  55. procedure CopyEnv(Src, Dest : EnvRec);
  56.   {-Copy contents of Src environment to Dest environment}
  57.  
  58. function EnvFree(Env : EnvRec) : Word;
  59.   {-Return bytes free in environment}
  60.  
  61. function GetEnvStr(Env : EnvRec; Search : string) : string;
  62.   {-Return a string from the environment}
  63.  
  64. function SetEnvStr(Env : EnvRec; Search, Value : string) : Boolean;
  65.   {-Set environment string, returning true if successful}
  66.  
  67. procedure DumpEnv(Env : EnvRec);
  68.   {-Dump the environment to StdOut}
  69.  
  70. function ProgramStr : string;
  71.   {-Return the complete path to the current program, '' if DOS < 3.0}
  72.  
  73. function SetProgramStr(Env : EnvRec; Path : string) : Boolean;
  74.   {-Add a program name to the end of an environment if sufficient space}
  75.  
  76.   {$IFDEF UseTpro}
  77. function ShellWithPrompt(Prompt : string) : Integer;
  78.   {-Shell to DOS with a new prompt}
  79.   {$ENDIF}
  80.  
  81.   {===============================================================}
  82.  
  83. implementation
  84.  
  85. type
  86.   SO =
  87.     record
  88.       O : Word;
  89.       S : Word;
  90.     end;
  91.  
  92.   procedure ClearEnvRec(var Env : EnvRec);
  93.     {-Initialize an environment record}
  94.   begin
  95.     FillChar(Env, SizeOf(Env), 0);
  96.   end;
  97.  
  98.   procedure MasterEnv(var Env : EnvRec);
  99.     {-Return master environment record}
  100.   var
  101.     Owner : Word;
  102.     Mcb1 : Word;
  103.     Mcb2 : Word;
  104.     Done : Boolean;
  105.   begin
  106.     with Env do begin
  107.       ClearEnvRec(Env);
  108.  
  109.       {Interrupt $2E points into COMMAND.COM}
  110.       Owner := MemW[0:(2+4*$2E)];
  111.  
  112.       {Mcb1 points to memory control block for COMMAND}
  113.       Mcb1 := Owner-1;
  114.       if (Mem[Mcb1:0] <> Byte('M')) or (MemW[Mcb1:1] <> Owner) then
  115.         Exit;
  116.  
  117.       {Get segment of next block}
  118.       Mcb2 := Owner+MemW[Mcb1:3];
  119.  
  120.       repeat
  121.         if Mem[Mcb2:0] <> Byte('M') then
  122.           {Not a memory control block, we're lost}
  123.           Exit
  124.         else if MemW[Mcb2:1] = Owner then
  125.           {Found it}
  126.           Done := True
  127.         else if MemW[Mcb2:1] = 0 then begin
  128.           {A free block, move to next block and look again}
  129.           Done := False;
  130.           Mcb2 := Mcb2+1+MemW[Mcb2:3];
  131.         end else
  132.           {Unknown error}
  133.           Exit;
  134.       until Done;
  135.  
  136.       {Return segment and length of environment}
  137.       EnvSeg := Mcb2+1;
  138.       EnvLen := MemW[Mcb2:3] shl 4;
  139.     end;
  140.   end;
  141.  
  142.   procedure CurrentEnv(var Env : EnvRec);
  143.     {-Return current environment record}
  144.   var
  145.     ESeg : Word;
  146.     Mcb : Word;
  147.   begin
  148.     with Env do begin
  149.       ClearEnvRec(Env);
  150.       ESeg := MemW[PrefixSeg:$2C];
  151.       Mcb := ESeg-1;
  152.       if (Mem[Mcb:0] <> Byte('M')) or (MemW[Mcb:1] <> PrefixSeg) then
  153.         Exit;
  154.       EnvSeg := ESeg;
  155.       EnvLen := MemW[Mcb:3] shl 4;
  156.     end;
  157.   end;
  158.  
  159.   procedure NewEnv(var Env : EnvRec; Size : Word);
  160.     {-Allocate a new environment (on the heap)}
  161.   var
  162.     Mcb : Word;
  163.   begin
  164.     with Env do
  165.       if MaxAvail < Size+31 then
  166.         {Insufficient space}
  167.         ClearEnvRec(Env)
  168.       else begin
  169.         {31 extra bytes for paragraph alignment, fake MCB}
  170.         GetMem(EnvPtr, Size+31);
  171.         EnvSeg := SO(EnvPtr).S+1;
  172.         if SO(EnvPtr).O <> 0 then
  173.           Inc(EnvSeg);
  174.         EnvLen := Size;
  175.         {Fill it with nulls}
  176.         FillChar(EnvPtr^, Size+31, 0);
  177.         {Make a fake MCB below it}
  178.         Mcb := EnvSeg-1;
  179.         Mem[Mcb:0] := Byte('M');
  180.         MemW[Mcb:1] := PrefixSeg;
  181.         MemW[Mcb:3] := (Size+15) shr 4;
  182.       end;
  183.   end;
  184.  
  185.   procedure DisposeEnv(var Env : EnvRec);
  186.     {-Deallocate an environment previously allocated on heap}
  187.   begin
  188.     with Env do
  189.       if EnvPtr <> nil then begin
  190.         FreeMem(EnvPtr, EnvLen+31);
  191.         ClearEnvRec(Env);
  192.       end;
  193.   end;
  194.  
  195.   procedure SetCurrentEnv(Env : EnvRec);
  196.     {-Specify a different environment for the current program}
  197.   begin
  198.     with Env do
  199.       if EnvSeg <> 0 then
  200.         MemW[PrefixSeg:$2C] := EnvSeg;
  201.   end;
  202.  
  203.   procedure CopyEnv(Src, Dest : EnvRec);
  204.     {-Copy contents of Src environment to Dest environment}
  205.   var
  206.     Size : Word;
  207.     SPtr : EnvArrayPtr;
  208.     DPtr : EnvArrayPtr;
  209.   begin
  210.     if (Src.EnvSeg = 0) or (Dest.EnvSeg = 0) then
  211.       Exit;
  212.  
  213.     if Src.EnvLen <= Dest.EnvLen then
  214.       {Space for the whole thing}
  215.       Size := Src.EnvLen
  216.     else
  217.       {Take what fits}
  218.       Size := Dest.EnvLen-1;
  219.  
  220.     SPtr := Ptr(Src.EnvSeg, 0);
  221.     DPtr := Ptr(Dest.EnvSeg, 0);
  222.     Move(SPtr^, DPtr^, Size);
  223.     FillChar(DPtr^[Size], Dest.EnvLen-Size, 0);
  224.   end;
  225.  
  226.   procedure SkipAsciiZ(EPtr : EnvArrayPtr; var EOfs : Word);
  227.     {-Skip to end of current AsciiZ string}
  228.   begin
  229.     while EPtr^[EOfs] <> #0 do
  230.       Inc(EOfs);
  231.   end;
  232.  
  233.   function EnvNext(EPtr : EnvArrayPtr) : Word;
  234.     {-Return the next available location in environment at EPtr^}
  235.   var
  236.     EOfs : Word;
  237.   begin
  238.     EOfs := 0;
  239.     if EPtr <> nil then begin
  240.       while EPtr^[EOfs] <> #0 do begin
  241.         SkipAsciiZ(EPtr, EOfs);
  242.         Inc(EOfs);
  243.       end;
  244.     end;
  245.     EnvNext := EOfs;
  246.   end;
  247.  
  248.   function EnvFree(Env : EnvRec) : Word;
  249.     {-Return bytes free in environment}
  250.   begin
  251.     with Env do
  252.       if EnvSeg <> 0 then
  253.         EnvFree := EnvLen-EnvNext(Ptr(EnvSeg, 0))-1
  254.       else
  255.         EnvFree := 0;
  256.   end;
  257.  
  258.   {$IFNDEF UseTpro}
  259.   function StUpcase(S : string) : string;
  260.     {-Uppercase a string}
  261.   var
  262.     SLen : byte absolute S;
  263.     I : Integer;
  264.   begin
  265.     for I := 1 to SLen do
  266.       S[I] := UpCase(S[I]);
  267.     StUpcase := S;
  268.   end;
  269.   {$ENDIF}
  270.  
  271.   function SearchEnv(EPtr : EnvArrayPtr;
  272.                      var Search : string) : Word;
  273.     {-Return the position of Search in environment, or $FFFF if not found.
  274.       Prior to calling SearchEnv, assure that
  275.         EPtr is not nil,
  276.         Search is not empty
  277.     }
  278.   var
  279.     SLen : Byte absolute Search;
  280.     EOfs : Word;
  281.     MOfs : Word;
  282.     SOfs : Word;
  283.     Match : Boolean;
  284.   begin
  285.     {Force upper case search}
  286.     Search := StUpcase(Search);
  287.  
  288.     {Assure search string ends in =}
  289.     if Search[SLen] <> '=' then begin
  290.       Inc(SLen);
  291.       Search[SLen] := '=';
  292.     end;
  293.  
  294.     EOfs := 0;
  295.     while EPtr^[EOfs] <> #0 do begin
  296.       {At the start of a new environment element}
  297.       SOfs := 1;
  298.       MOfs := EOfs;
  299.       repeat
  300.         Match := (EPtr^[EOfs] = Search[SOfs]);
  301.         if Match then begin
  302.           Inc(EOfs);
  303.           Inc(SOfs);
  304.         end;
  305.       until not Match or (SOfs > SLen);
  306.  
  307.       if Match then begin
  308.         {Found a match, return index of start of match}
  309.         SearchEnv := MOfs;
  310.         Exit;
  311.       end;
  312.  
  313.       {Skip to end of this environment string}
  314.       SkipAsciiZ(EPtr, EOfs);
  315.  
  316.       {Skip to start of next environment string}
  317.       Inc(EOfs);
  318.     end;
  319.  
  320.     {No match}
  321.     SearchEnv := $FFFF;
  322.   end;
  323.  
  324.   procedure GetAsciiZ(EPtr : EnvArrayPtr; var EOfs : Word; var EStr : string);
  325.     {-Collect AsciiZ string starting at EPtr^[EOfs]}
  326.   var
  327.     ELen : Byte absolute EStr;
  328.   begin
  329.     ELen := 0;
  330.     while (EPtr^[EOfs] <> #0) and (ELen < 255) do begin
  331.       Inc(ELen);
  332.       EStr[ELen] := EPtr^[EOfs];
  333.       Inc(EOfs);
  334.     end;
  335.   end;
  336.  
  337.   function GetEnvStr(Env : EnvRec; Search : string) : string;
  338.     {-Return a string from the environment}
  339.   var
  340.     SLen : Byte absolute Search;
  341.     EPtr : EnvArrayPtr;
  342.     EOfs : Word;
  343.     EStr : string;
  344.     ELen : Byte absolute EStr;
  345.   begin
  346.     with Env do begin
  347.       ELen := 0;
  348.       if (EnvSeg <> 0) and (SLen <> 0) then begin
  349.         {Find the search string}
  350.         EPtr := Ptr(EnvSeg, 0);
  351.         EOfs := SearchEnv(EPtr, Search);
  352.         if EOfs <> $FFFF then begin
  353.           {Skip over the search string}
  354.           Inc(EOfs, SLen);
  355.           {Build the result string}
  356.           GetAsciiZ(EPtr, EOfs, EStr);
  357.         end;
  358.       end;
  359.       GetEnvStr := EStr;
  360.     end;
  361.   end;
  362.  
  363.   function SetEnvStr(Env : EnvRec; Search, Value : string) : Boolean;
  364.     {-Set environment string, returning true if successful}
  365.   var
  366.     SLen : Byte absolute Search;
  367.     VLen : Byte absolute Value;
  368.     EPtr : EnvArrayPtr;
  369.     ENext : Word;
  370.     EOfs : Word;
  371.     MOfs : Word;
  372.     OldLen : Word;
  373.     NewLen : Word;
  374.     NulLen : Word;
  375.   begin
  376.     with Env do begin
  377.       SetEnvStr := False;
  378.       if (EnvSeg = 0) or (SLen = 0) then
  379.         Exit;
  380.       EPtr := Ptr(EnvSeg, 0);
  381.  
  382.       {Find the search string}
  383.       EOfs := SearchEnv(EPtr, Search);
  384.  
  385.       {Get the index of the next available environment location}
  386.       ENext := EnvNext(EPtr);
  387.  
  388.       {Get total length of new environment string}
  389.       NewLen := SLen+VLen;
  390.  
  391.       if EOfs <> $FFFF then begin
  392.         {Search string exists}
  393.         MOfs := EOfs+SLen;
  394.         {Scan to end of string}
  395.         SkipAsciiZ(EPtr, MOfs);
  396.         OldLen := MOfs-EOfs;
  397.         {No extra nulls to add}
  398.         NulLen := 0;
  399.       end else begin
  400.         OldLen := 0;
  401.         {One extra null to add}
  402.         NulLen := 1;
  403.       end;
  404.  
  405.       if VLen <> 0 then
  406.         {Not a pure deletion}
  407.         if ENext+NewLen+NulLen >= EnvLen+OldLen then
  408.           {New string won't fit}
  409.           Exit;
  410.  
  411.       if OldLen <> 0 then begin
  412.         {Overwrite previous environment string}
  413.         Move(EPtr^[MOfs+1], EPtr^[EOfs], ENext-MOfs-1);
  414.         {More space free now}
  415.         Dec(ENext, OldLen+1);
  416.       end;
  417.  
  418.       {Append new string}
  419.       if VLen <> 0 then begin
  420.         Move(Search[1], EPtr^[ENext], SLen);
  421.         Inc(ENext, SLen);
  422.         Move(Value[1], EPtr^[ENext], VLen);
  423.         Inc(ENext, VLen);
  424.       end;
  425.  
  426.       {Clear out the rest of the environment}
  427.       FillChar(EPtr^[ENext], EnvLen-ENext, 0);
  428.  
  429.       SetEnvStr := True;
  430.     end;
  431.   end;
  432.  
  433.   procedure DumpEnv(Env : EnvRec);
  434.     {-Dump the environment to StdOut}
  435.   var
  436.     EOfs : Word;
  437.     EPtr : EnvArrayPtr;
  438.   begin
  439.     with Env do begin
  440.       if EnvSeg = 0 then
  441.         Exit;
  442.       EPtr := Ptr(EnvSeg, 0);
  443.       EOfs := 0;
  444.       WriteLn;
  445.       while EPtr^[EOfs] <> #0 do begin
  446.         while EPtr^[EOfs] <> #0 do begin
  447.           Write(EPtr^[EOfs]);
  448.           Inc(EOfs);
  449.         end;
  450.         WriteLn;
  451.         Inc(EOfs);
  452.       end;
  453.       WriteLn('Bytes free: ', EnvFree(Env));
  454.     end;
  455.   end;
  456.  
  457.   function DosVersion : Word;
  458.     {-Return the DOS version, major part in AX}
  459.   inline(
  460.          $B4/$30/                 {mov ah,$30}
  461.          $CD/$21/                 {int $21}
  462.          $86/$C4);                {xchg ah,al}
  463.  
  464.   function ProgramStr : string;
  465.     {-Return the name of the current program, '' if DOS < 3.0}
  466.   var
  467.     EOfs : Word;
  468.     Env : EnvRec;
  469.     EPtr : EnvArrayPtr;
  470.     PStr : string;
  471.   begin
  472.     ProgramStr := '';
  473.     if DosVersion < $0300 then
  474.       Exit;
  475.     CurrentEnv(Env);
  476.     if Env.EnvSeg = 0 then
  477.       Exit;
  478.     {Find the end of the current environment}
  479.     EPtr := Ptr(Env.EnvSeg, 0);
  480.     EOfs := EnvNext(EPtr);
  481.     {Skip to start of path name}
  482.     Inc(EOfs, 3);
  483.     {Collect the path name}
  484.     GetAsciiZ(EPtr, EOfs, PStr);
  485.     ProgramStr := PStr;
  486.   end;
  487.  
  488.   function SetProgramStr(Env : EnvRec; Path : string) : Boolean;
  489.     {-Add a program name to the end of an environment if sufficient space}
  490.   var
  491.     PLen : Byte absolute Path;
  492.     EOfs : Word;
  493.     Numb : Word;
  494.     EPtr : EnvArrayPtr;
  495.   begin
  496.     SetProgramStr := False;
  497.     with Env do begin
  498.       if EnvSeg = 0 then
  499.         Exit;
  500.       {Find the end of the current environment}
  501.       EPtr := Ptr(EnvSeg, 0);
  502.       EOfs := EnvNext(EPtr);
  503.       {Assure space for path}
  504.       if EnvLen < PLen+EOfs+4 then
  505.         Exit;
  506.       {Put in the count field}
  507.       Inc(EOfs);
  508.       Numb := 1;
  509.       Move(Numb, EPtr^[EOfs], 2);
  510.       {Skip to start of path name}
  511.       Inc(EOfs, 2);
  512.       {Move the path into place}
  513.       Path := StUpcase(Path);
  514.       Move(Path[1], EPtr^[EOfs], PLen);
  515.       {Null terminate}
  516.       Inc(EOfs, PLen);
  517.       EPtr^[EOfs] := #0;
  518.       SetProgramStr := True;
  519.     end;
  520.   end;
  521.  
  522.   {$IFDEF UseTpro}
  523.   function ShellWithPrompt(Prompt : string) : Integer;
  524.     {-Shell to DOS with a new prompt}
  525.   const
  526.     PromptStr : string[7] = 'PROMPT=';
  527.   var
  528.     PLen : Byte absolute Prompt;
  529.     NSize : Word;
  530.     Status : Integer;
  531.     CE : EnvRec;
  532.     NE : EnvRec;
  533.     OldP : string;
  534.     OldPLen : Byte absolute OldP;
  535.   begin
  536.     {Point to current environment}
  537.     CurrentEnv(CE);
  538.     if CE.EnvSeg = 0 then begin
  539.       {Error getting environment}
  540.       ShellWithPrompt := -5;
  541.       Exit;
  542.     end;
  543.  
  544.     {Compute size of new environment}
  545.     OldP := GetEnvStr(CE, PromptStr);
  546.     NSize := CE.EnvLen;
  547.     if OldPLen < PLen then
  548.       Inc(NSize, PLen-OldPLen);
  549.  
  550.     {Allocate and initialize a new environment}
  551.     NewEnv(NE, NSize);
  552.     if NE.EnvSeg = 0 then begin
  553.       {Insufficient memory for new environment}
  554.       ShellWithPrompt := -6;
  555.       Exit;
  556.     end;
  557.     CopyEnv(CE, NE);
  558.  
  559.     {Get the program name from the current environment}
  560.     OldP := ProgramStr;
  561.  
  562.     {Set the new prompt string}
  563.     if not SetEnvStr(NE, PromptStr, Prompt) then begin
  564.       {Program error, should have enough space}
  565.       ShellWithPrompt := -7;
  566.       Exit;
  567.     end;
  568.  
  569.     {Transfer program name to new environment if possible}
  570.     if not SetProgramStr(NE, OldP) then
  571.       ;
  572.  
  573.     {Point to new environment}
  574.     SetCurrentEnv(NE);
  575.  
  576.     {Shell to DOS with new prompt in place}
  577.     Status := ExecDos('', True, ShellUserProc);
  578.  
  579.     {Restore previous environment}
  580.     SetCurrentEnv(CE);
  581.  
  582.     {Release the heap space}
  583.     if Status >= 0 then
  584.       DisposeEnv(NE);
  585.  
  586.     {Return exec status}
  587.     ShellWithPrompt := Status;
  588.   end;
  589.   {$ENDIF}
  590.  
  591. end.
  592.